﻿/**********************************************************************************
Heading: Triframe Environment
Version: 0.1
Author: Scott Underhill
Description: 

The following is the triframe environment is uses a MVC javascript which is communicating through Ajax language library to the backend environmental path. 
Setup: 
1. As the site works of webservices, a dedicated backend web service environment needs to be setup 
2. Jquery is required for the javascript to run 
**********************************************************************************/

/* #Region: Helper Functions */

// Class:GetPropetires
// Arg: Any object
// Returns an associated array of members which are declared public in a class

var debug = false;

function triframe_ScrollMe(target) {
    jQuery('html,body').animate({ scrollTop: jQuery(target).offset().top }, 100);
}

function GetPropetires(obj) {
    var props = new Array();
    for (var s in obj) {
        if (typeof (obj[s]) != "function") {
            props[props.length] = s;
        }
    }
    return props;
}

// Converts a strong enchoded bu object to string to an array
function StringToArray(stringEnchoded, arrayObject) {
try{
    var i = 0;
    var tmp = new Array();
    tmp = stringEnchoded.split("&")
    for (var item in tmp) {
        var substring = tmp[item];
        arrayObject[substring.split("@")[0]] = substring.split("@")[1];        
    }
    }catch(exeption) {
    }
}

// Class:StringToObject
// Arg1:encoded string
// Converts an encoded string to an object. Normally send over ajax
function StringToObject(stringEncoded, object) {
    var items = GetPropetires(object)
    for (var property in items) {
        var subString = stringEncoded.split(items[property] + "@")[1];
        var valueItem = subString.split(items[property] + "&")[0];
        object[items[property]] = valueItem;
    }
}

// Class:ObjectToString
// Arg1:objec to encode 
// Converts an object to an encoded string to send over ajax
function ObjectToString(object) {
    var items = GetPropetires(object)
    var responseString = "";
    for (var property in items) {
        responseString += items[property] + "@" + object[items[property]] + "&";
    }
    return responseString;
}



/* #Region: Environment Classes - Data Objects */

// Class:Triple
// Triple is responsable for the core representation of all data 
Triple = function() {
    var index = 0;
    var t1; // Instance Class or identification field 
    var t2; // Schema Slot Gui
    var t3; // Value
}


// Class: CollectionTriple 
// Represents the collection type of the triples 
function CollectionTriple() {

    // Makes a single string key from triples (t3 is value, and not part of the key)
    function MakeKey(triple) {
        return triple.index + ":" + triple.t1 + ":" + triple.t2;
    }

    // Returns a string representing triples from an instance class     
    function MakeValue(instanceIdMatch) {
        var exportString = "";
        for (var i in this.Triples) {
            if (i.match(instanceIdMatch) != null) {
                exportString = exportString + i + ":" + this.Triples[i] + "@@";
            }
        }
        return exportString;
    }
    
    // Makes Public 
    this.MakeKey = MakeKey;
    this.MakeValue = MakeValue;


    /*
    * Represents, the collection of trips in the system 
    * NOTE: These are not in use at the moment 
    */
    this.Triples = new Array();
    this.Undo = new Array();
    this.Redo = new Array();
}

/* 
 * This create a single data model for all items 
 */
var Triples = new CollectionTriple();

// Class Decleration 
triFrame = function() {}

// Class Decleration
Instanceclass = function() {}

// Implementation of Instance Class 
$.extend(Instanceclass.prototype, {
    _fromInstance: '',
    _fromSchema: '',
    _throughSlot: '',
    _isNew: '',
    _instanceId: '',
    _sid: '',

    // Constructs the class fron a "specific" encoded string. (Note: This doesnt use the standered encoding)
    ConstructFromString: function(stringCode) {
        var parts = new Array();
        parts = stringCode.split('&');
        this._fromInstance = parts[0].split('@')[1];
        this._fromSchema = parts[1].split('@')[1];
        this._throughSlot = parts[2].split('@')[1];
        this._isNew = parts[3].split('@')[1];
        this._instanceId = parts[4].split('@')[1];
        this._sid = parts[5].split('@')[1];

    },
    // Construct from properties. Currently avoiding this method, and string is easier to communicate 
    Construct: function(fromInstance, fromSchema, throughSlot, isNew, id, sid) {
        this._fromInstance = fromInstance;
        this._fromSchema = fromSchema;
        this._throughSlot = throughSlot;
        this._isNew = isNew;
        this._instanceId = id;
        this._sid = sid;
    },
    // Creates the encoded string 
    CreateString: function() {
        var returnStrung = "f_ic@" + this._fromInstance + "&f_sc@" + this._fromSchema + "&f_sl@" + this._throughSlot + "&n@" + this._isNew + "&ic@" + this._instanceId + "&sid@" + this._sid;
        return returnStrung;
    }
});


function ConstructScript(script) {
    var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
    var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
    var bMoz = (navigator.appName == 'Netscape');

    try {
        var x = document.createElement("script");
        x.type = "text/javascript";

        /* In IE we must use .text! */
        if ((bSaf) || (bOpera) || (bMoz))
            x.innerHTML = script;
        else x.text = script;

        document.getElementsByTagName("head")[0].appendChild(x);
    } catch (e) {
        alert(e);
    }
}
                    
// Class Decleration: A watcher is a function which can watch data on change. 
watch = function() { }

// Watcher Implementation
$.extend(watch.prototype, {
    _watching: '',
    _saving: '',
    _error: '',
    Initalise: function() {
        this._error = new Array();
        $('body').bind("datachange", function(e, data, control) {
            $(this._watching[control]).val(data);
        });
    },
    AddWatcher: function(triple, textcontroller) {
        this._watching[triple] = textcontroller;
        controller.AddTriples(triple);
        $('#' + textcontroller).change(function() {
            controller.UpdateData(triple, $(this).val());
        })
    },
    AddSave: function(instanceId, buttonController, formId) {
        if (debug) {
            alert('inSave');
        }
        this._saving[instanceId] = buttonController;
        $('#' + buttonController).click(function() {
            controller.SaveData(instanceId, formId);
        })
    },
    AddError: function(instanceId, buttonController) {
        this._error[instanceId] = buttonController;
    },
    getError: function(instanceId) {
        return this._error[instanceId];
    }
})

// Implementation of the core triframe engine
$.extend(triFrame.prototype, {
    _triFrameCollection: '',
    watcher: '',
    _instanceClasses: '',
    hasInitalised: false,
    Initalise: function() {
        this._instanceClasses = new Array();
        this.watcher = new watch();
        this.watcher.Initalise();
        hasInitalised = true;
        if (debug) {
            alert('start');
        }
    },
    AddTriples: function(triple) {
        var key = Triples.MakeKey(triple);
        if (Triples.Triples[key] == null) {
            Triples.Triples[key] = triple.t3;
        }
    },
    AddInstanceClass: function(instanceClass) {
        this._instanceClasses[instanceClass._instanceId] = instanceClass;
    },
    getWatcher: function() {
        return this.watcher;
    },
    SaveData: function(instanceClassId, formid) {
        // Creates the request object to send to the server 
        request = new Request;
        request.formid = formid;
        request.action = "save";

        // Gets the associated data 
        var icToSave = this._instanceClasses[instanceClassId];
        var com = "{'ic':'" + icToSave.CreateString() + "','data':'" + Triples.MakeValue(instanceClassId) + "','request':'" + ObjectToString(request) + "'  }"
        var info = $.ajax({
            type: 'POST',
            url: basepath + 'Environment.asmx/SaveData2',
            data: com,
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            timeout: 50000, /* Timeout in ms */
            id: instanceClassId, /* Timeout in ms */
            success: function(data) {
                // The server will return an encoded view object 
                var view = new View;
                StringToObject(data.d, view);

                // There is a standard error stream 
                if (view.status == "error") {
                    $('#' + formid).find('#error').hide();
                    $('#' + formid).find('#error').text('');
                    $('#' + formid).find('#error').append(view.content);
                    $('#' + formid).find('#error').show('highlight');
                } else {
                    // All other processing in the save action will use a replace 
                    $('#' + formid).text('');
                    $('#' + formid).append(view.content);

                }
            }
        })
    },

    // Resposable for calling the web service 
    ConstructControl3: function(instanceClassGuid, schemaGuid, throughGuid, slotTargertId, formID, targetControl, controlToLoad, mode) {
        $.ajax({
            type: 'POST',
            url: basepath + 'Environment.asmx/ConstructControl3',
            data: "{'instanceClassGuid':'" + instanceClassGuid + "','schemaGuid':'" + schemaGuid + "','throughGuid':'" + throughGuid + "','slotId':'" + slotTargertId + "', 'controlToLoad':'" + controlToLoad + "','mode':'" + mode + "' }",
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            timeout: 50000, /* Timeout in ms */
            TargetId: targetControl,
            TargetAreaId: formID,
            Mode: mode,
            beforeSend: function(data) {
                $('#' + this.TargetAreaId).find('#' + this.TargetId).append("<img src='../images/ajax-loader.gif' />");
            },
            success: function(data) {
                var view = new View;
                StringToObject(data.d, view);
                if (view.status == "error") {
                    // Stream for error handling
                    // Given this is from construct on the first request, this is something new entering the environment. 
                    // So, I dont think this needs to be handled at this point in time 
                } else {
                    // Handel everything else

                    // Clears the target space
                    $('#' + this.TargetAreaId).find('#' + this.TargetId).text('');
                    // Adds the html
                    $('#' + this.TargetAreaId).find('#' + this.TargetId).append(view.content);


                    // Container modification
                    // This is done from here, rather than the return action as its part of the containment                    
                    // TODO: Add in transintions as well.
                    if (this.Mode == "popup") {
                        $('#' + this.TargetAreaId).find('#' + 'close').click(function() {
                            if (debug) {
                                alert("inclose");
                            }
                            $('#' + view.formid).dialog('close');
                        });

                        $('#' + this.TargetAreaId).find('#' + view.formid).dialog(
                       { bgiframe: true,
                           width: 600,
                           modal: true,
                           open: function(event, ui) {
                               // Make sure to construct script after popup
                               ConstructScript(view.script);
                           }

                       });
                    } else {
                        ConstructScript(view.script);
                    }
                }
            }
        });
    },
    // TODO: I dont think this is being used. 
    ConstructControl2: function(instanceClassGuid, schemaGuid, throughGuid, formID, targetControl, controlToLoad) {
        $.ajax({
            type: 'POST',
            url: '/Environment.aspx/ConstructControl2',
            data: "{'instanceClassGuid':'" + instanceClassGuid + "','schemaGuid':'" + schemaGuid + "','throughGuid':'" + throughGuid + "','controlToLoad':'" + controlToLoad + "'}",
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            timeout: 50000, /* Timeout in ms */
            TargetId: targetControl,
            TargetAreaId: formID,
            beforeSend: function(data) {
                // alert('#' + this.TargetAreaId + " > " + '#' + this.TargetId);
                $('#' + this.TargetAreaId).find('#' + this.TargetId).append("<img src='../images/ajax-loader.gif' />");
            },
            success: function(data) { /* called when request to barge.php completes */
                var str = "<div><script type='text/javascript'>alert('i am here');<\/script></div>";
                $('#' + this.TargetAreaId).find('#' + this.TargetId).text('');
                $('#' + this.TargetAreaId).find('#' + this.TargetId).append(data.d);
            }
        });
    },
    // TODO: I dont think this is being used 
    ConstructControl: function(controlName, returnControlId, controlId, idRepresenting, sid, from, froms, slid) {
        // fromi,string fs,string slotid, string id, string sid, bool isNew, string control
        $.ajax({
            type: 'POST',
            url: 'Environment.aspx/ConstructControl',
            data: "{'name':'" + controlName + "','process':'" + controlId + "','id':'" + idRepresenting + "','sid':'" + sid + "','from':'" + from + "','froms':'" + froms + "','slid':'" + slid + "'}",
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            timeout: 50000, /* Timeout in ms */
            TargetId: returnControlId,
            beforeSend: function(data) {
                $('#' + this.TargetId).append("<img src='../images/ajax-loader.gif' />");
            },
            success: function(data) { /* called when request to barge.php completes */
                var str = "<div><script type='text/javascript'>alert('i am here');<\/script></div>";
                $('#' + this.TargetId).text('');
                $('#' + this.TargetId).append(data.d);
            }
        });
    },

    // Broadcast will send generic information to anyone who is interested.
    // Data can be anything at the moment   
    Broadcast: function(action, id, data) {
        $('body').trigger("broadcast", [id, data]);
    },
    UpdateData2: function(t1, t2, data) {
        var t = new Triple();
        t.t1 = t1;
        t.t2 = t2;
        this.UpdateData(t, data);
    },
    UpdateData: function(tripleElement, data) {
        if (debug) {
            alert(tripleElement);
        }
        //  $('body').trigger("datachange", [tripleElement, "i3"]);
        if (Triples.Triples[Triples.MakeKey(tripleElement)] != null) {
            Triples.Triples[Triples.MakeKey(tripleElement)] = data;
        }
        if (this._instanceClasses[tripleElement.t1] != null) {
            // This is to find out if the instance class exist or not. If it does, I will trigger an instanceclass change, and child class change
            var instanceClassItem = this._instanceClasses[tripleElement.t1];
            // cascade to parent that child was saved
            $('body').trigger("childsaved", [instanceClassItem._throughSlot]);
        }

        // Need to Trigger events here 

        // Triples.Undo[Triples.MakeKey(tripleElement)] = tripleElement.t3;
        // var commandField = $get(this._commandFieldID);
        // commandField.value = "update";    
        // var dataField = $get(this._commandValueID);
        // dataField.value = tripleElement.t1 + ":" + tripleElement.t2 + ":" + tripleElement.t3;
        // postValidation();	
    },
    CallBackend: function(tripleElement) {
        // Process has dependancy I guess, in which sends a string of triples, and returns a stream of trips 

    }
});

View = function() {
    // private decleration 
    
    // Statue := [error | replace  | custom ]
    var status = "";
    // Content for render
    var content = "";
    // FormID of content
    var formid = "";    
    // Not in use
    var modelid = "";
    // Javascript to render after the Html render
    var script = "";
    
    // public decleration 
    this.status = status;
    this.content = content;
    this.formid = formid;
    this.modelid = modelid;
    this.script = script;
}

// The reqiest is the information going from the client to the server 
Request = function() {
    var formid = "";
    var action = "";

    this.formid = formid;
    this.action = action;
}


// Initalise the controller 
var controller = new triFrame();
$(document).ready(function() {

   controller.Initalise();
    $('body').bind("broadcast", function(e, name, data) {
      //  $('#job_basket_items').append(name);
    });
   // controller.Broadcast("mememe", "data");

});

/* NOT IN USE AT THE MOMENT */

// TODO: Implement at a later date 
// Trigger is anything which reacts in the enviornment, such as button or otherwise 
Trigger = function() {
    // Trigger is a instance slot, which represents a trigger
    // t2 = state | State could be changed or something else. Not sure yet 
}

/*
* A process is something which executes for a specific value or controller 
* May implement at a later date 
*/
process = function() { }


// Not in use
schemaslot = function() { }

// Not in use
schemaclass = function() { }

// Not in use 
ruleengine = function() { }

// Not in use 
workflowState = function() {
    this.workFlowListenr();
    this.workFlowAction();
}

// Not in use 
workflow = function() { }

// Not in use
function workFlowElement() {
    var processName = '';
    var instanceClassRepresenting = '';

    function Initalise(processName, instanceRepresenting) {
        this.processName = processName;
        this.instanceClassRepresenting = instanceRepresenting;
    }
    this.Initalise = Initalise;
}

$.extend(workflow.prototype, {
    // Workflow elements 
    // Arg [Optional]  Representing an instance class / process to call 
    // Return true / false 
    _workFlowItems: Array(),
    Initalise: function() {
        // Load first workflow
    }

})







/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/

/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
*       used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
*                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
*                             If set to null or omitted, the cookie will be a session cookie and will not be retained
*                             when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
*                        require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/

/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};
