/*

WO (singleton) - top level object/namespace for WebOn javascript

Dependencies:

    Prototype version 1.6 and above

    WebOn functions needed (must be publicly exposed for the relevant interface):

        config.get

        _d_common.get_value
        _d_common.set_value
        _d_common.unset_value

Usage:

     <script src="/WO/javascript/prototype/protoscript.js"></script>

     <script>
         var WO_CONFIG_URL = '[:script.current:]func=config.get&debug=off&output=json';
     </script>

     <script src="/WO/javascript/WO/WO.js"></script>

     (add script tags for adding widgets etc. to global namespace, e.g. <script src="/WO/javascript/WO/widgets/grid.js"></script>

     Special WO_ JavaScript variables that can be set in the global scope before including WO.js:

        WO_CONFIG_URL   -   Must be present, and this format:

                                var WO_CONFIG_URL = '[:script.current:]func=config.get&debug=off&output=json';

        WO_START        -   WO_START = new Date(); // Used for timing performance.
                            If set, it will be logged in the WO.console constructor.

        WO_MAIN_INIT    -   If a function with this name is defined, it will override the WO.main_init function.

                            The main_init function is used for initializing widgets and picking up WO.store values from document.body
                            when the WO object is instantiated.

                            It is called only once, when document.dom:loaded event first fires.

                            This is useful if special functionality is needed in the main_init procedure.

                            The overriding WO_MAIN_INIT function must minimally contain this code:

                              WO.init(); // Pick up WO.store values and initialize widgets in document.body

                              document.stopObserving('dom:loaded',WO_MAIN_INIT); // make sure WO_MAIN_INIT is called only once

                            The overridden WO_MAIN_INIT function can also be used to override other methods of the WO object,
                            for instance it is possible to override the WO.init function by using this code:

                                    function WO_MAIN_INIT(e) {

                                                WO.init = function(oElem) {

                                                    // Overridden WO.init function - "this" refers to the WO object

                                                        this.console.log("Overridden WO.init function!");

                                                        if (! oElem) {  oElem = document.body; }
                                                        oElem = $(oElem);

                                                        // Pick up WO_store elements and populate WO_store accordingly

                                                            this.store_sync(oElem);

                                                        // Find and initialize widgets

                                                            this.widgets_create(oElem);


                                      } // End of definition for WO.init overriding function

                                      // Perform main init

                                      WO.init();
                                      document.stopObserving('dom:loaded',WO_MAIN_INIT);

                                      var body_elem = Ext.get(document.body);
                                      body_elem.on('click',WO.webon7.clickhandler);

                                      this.console.log("WO main_init end");
                                     }

             WO_INIT_BEFORE - If a function with this name is defined, it will be called at the beginning of the WO.init function

             WO_INIT_AFTER - If a function with this name is defined, it will be called at the end of the WO.init function



Properties:

    d_application (hash) - Contains public values from d_application.

        Values from application are exposed publicly by setting APPLICATION_PUBLIC in param.ini with a comma separated list
        of keys, in the same way as "setup"

    d_session (object)

        get (sKey,[bAjax]=true) Gets the d_session value for sKey.
                                If bAjax (optional, default=true) is false, the value is fetched from d_sessions store hash
                                If bAjax is true, the value is fetched with an Ajax call to the WebOn func _d_session.get

        set (sKey,vValue,[bAsync]=false)    Sets the d_session value for sKey, making an Ajax call to the WebOn func _d_session.set
                                            The Ajax call is synchronous as default (bAsync=false), but can be set to asynchronous by using true as the third parameter
                                            Returns true or false, depending on the success.


        unset (sKey,[bAsync]=false)         Removes the d_session value for sKey, making an Ajax call to the WebOn func _d_session.unset_value
                                            Returns true or false, depending on success

    d_user    (object)

        get (sKey,[bAjax]=true) Gets the d_session value for sKey.
                                If bAjax (optional, default=true) is false, the value is fetched from d_sessions store hash
                                If bAjax is true, the value is fetched with an Ajax call to the WebOn func _d_session.get

        set (sKey,vValue,[bAsync]=false)        Sets the d_session value for sKey, making an Ajax call to the WebOn func _d_session.set
                                                The Ajax call is synchronous as default (bAsync=false), but can be set to asynchronous by using true as the third parameter
                                                Returns true or false, depending on the success.

        unset (sKey,[bAsync]=false)             Removes the d_session value for sKey, making an Ajax call to the WebOn func _d_session.unset_value
                                                The Ajax call is synchronous as default (bAsync=false), but can be set to asyncnronous by using true as the third parameter
                                                Returns true or false, depending on success

    freetext_store     (hash)     - Contains freetext keys/values for the current user ($wo->{FREETEXT}{$wo->{SESSION}{LANGUAGECODE}})
    See documentation of freetext method below for examples of correctly using freetext

    interface    (string)    ('frontend','manager' or 'backend')

    param (hash)

        Contains keys/values for params defined as public.
        Publicly exposed parameters are defined as a comma separated list called PARAM_PUBLIC in param.ini.

        Example from param.ini:

            PARAM_PUBLIC    = customer_type,pcat_cgidir

            This will result in the params customer_type and pcat_cgidir being available in WO.param.customer_type and WO.param.pcat_cgidir


    setup (hash)

        inst     (string)   installation name

        ext      (string)   Extension for script, e.g. ".cgi"

        mediabank_ver (int   )   Mediabank version - 1 or 2

        mediabank_www (string)   Relative path to mediabank, e.g. "/utv62/mediabank/"

        script   (string)   Current script, e.g. "manager"

        server   (string)   alias for setup.url

        url      (string)   server name, eg. 'dev2.webon.net'

        ver      (string)   WebOn version, e.g. "WO62"

        version  (string)   WebOn version (long), e.g. "6_2_0"

        Additional values from $wo->{SETUP} can be exposed by defining the value SETUP_PUBLIC in param.ini,
        as a comma separated list of $wo->{SETUP} keys to be exposed.

        Example from param.ini:

            MYSPECIALPARAM = My special value
            MYSPECIALPARAM2 = My special value 2

            SETUP_PUBLIC    = MYSPECIALPARAM,MYSPECIALPARAM2

        All values in the setup hash are lowercased, so in the example above WO.setup.myspecialparam = 'My special value'


    script (hash)

        current (string)
        backend (string)
        manager (string)
        frontend (string)

    session (hash) - Contains values from WO.session

    store (hash) - Variable store (with possible namespaces)

    widgets (hash) -    Contains references to widget instances.
                        For instance, a widget with this markup:

                        <div class="wow_grid" id="mygrid"></div>

                        could be referenced with WO.widgets['mygrid'] after creation

Methods:

    main_init (e)      -    The main entry point for initializing widgets. Called automatically (only once) on dom:loaded
                            The event listener binding this func to dom:loaded is removed on the first call, so it will not be
                            called again.


                            If a function named WO_MAIN_INIT is defined before including WO.js, this function
                            will be used as the main_init function.

                            This is useful if special functionality is needed in the main_init procedure.

                            The overriding WO_MAIN_INIT function must minimally contain this code:

                              WO.init(); // Pick up WO.store values and initialize widgets in document.body

                              document.stopObserving('dom:loaded',WO_MAIN_INIT); // make sure WO_MAIN_INIT is called only once

    init ([oDOMnode])

        oDOMnode is optional - if not given, document.body is used.

        Picks up WO_store elements and initializes widgets found in oDOMnode

    freetext(sKey)

      Returns freetext string from the freetext_store hash if the key exists. If the key doesn't exist, sKey is returned.

    store_namespace(sNamespace)

        Creates WO.store[sNamespace].

        Returns 1 or 0, depending on success

        sNamespace can contain a deep namespace, with multiple namespaces separated with .

        Example:

            // Make sure namespace is defined

            WO.store_namespace('myspace.subspace');

            WO.store.myspace.subspace.myvalue = 'MyVal';

    store_set

        Sets a value in WO.store.

        Returns 1 or 0, depending on success

            sValue can be a single string or a JSON-encoded string

            If sNamespace is not given, sValue is stored directly in WO.store[sKey]

            sNamespace can contain a deep namespace, with multiple namespaces separated with .

            Examples :

                // No namespace

                    var success = WO.store_set('mykey','myvalue');
                    alert(WO.store.mykey);

                    var myhash = {key1:'value1',key2:'value2'};
                    var success = WO.store.set('mykey',myhash.toJSON());
                    alert(WO.store.mykey.key1);

                // Namespace

                    var success = WO.store_set('mykey','myvalue','myspace');
                    alert(WO.store.myspace.mykey);

                    var myhash = {key1:'value1',key2:'value2'};
                    var success = WO.store.set('mykey',myhash.toJSON(),'myspace');
                    alert(WO.store.myspace.mykey.key1);

    store_sync([oDOMElem])  - returns: 1

        Transfers values from hidden input fields in a DOM element to WO.store

        Returns: 1 for success for all elements, comma-separated list with name of failed elements (failed JSON-eval) if one or more elements fail

        oElem - DOM element. If not given, document.body is used

        Correct way of creating hidden input elements in par5 template for store:

            [: webon.js_store(sKey,vValue,[sNamespace]) :]

        webon.js_store will create hidden input elements on the following format:

            Format for hidden WO_store input fields (only for internal reference, please use webon.js_store method in templates, as outlined above!)

                <input type="hidden" class="WO_store" name="myvar" namespace="myspace" value="myvalue" />

                (Will cause WO.store.myspace to contain the value 'myvalue')

                The "namespace" attribute can contain deep namespaces - example:

                    <input type="hidden" class="WO_store" name="myvar" namespace="myspace.subspace" value="myvalue" />

                The "value" attribute can contain a single string or a JSON-encoded data structure - example:

                    <input type="hidden" class="WO_store" name="myvar" namespace="myspace.subspace" value="[:webon.toJSON(mystruct) | encode:]" />

                    Take note to filter the JSON string through encode, to correctly encode quotes

                store_sync will auto-detect whether the value is JSON-encoded, and act accordingly.


    widgets_create(oDOMnode)

        oDOMnode is optional - if not given, document.body is used.

        Finds all elements with a class name starting with "wow_" and call the constructor for each widget

        By convention, the class attribute of a widget should start with the widget type, e.g. "wow_grid", and other
        class names should follow.

        Examples of widget markup:

            <div id="mygrid" class="wow_grid" wow_params="columns:4,headings:['head1','head2','head3']">
            </div>

            <div id="mygrid" class="wow_grid">
                <div class="wow_params">
                    columns:4,
                    headings:['Head1','Head2','Head3','Head4']
                </div>
            </div>

         Widget instances are stored in WO.widgets[sName], where sName is the id of the widget's DOM node,
         or the widget name (e.g. "grid") if the DOM node has no id

*/

/*

 Extend DOM elements with the wowparams method - for reading wow_params and returning object hash or raw value

 Parameters (config hashes) for widgets have these possible markups:

 1. Inside the widget tag, as "wow_params" attribute

    <div class="wow_grid" id="mygrid" wow_params="columns:3,headings:['Head1','Head2','Head3']">
    </div>

 2. Inside a child node of the widget node, with the class "wow_params"

    <div class="wow_grid" id="mygrid">
        <div class="wow_params">
            columns:3,
            headings:['Head1','Head2','Head3']
        </div>
    </div>

 3. Inside an external dom node (typically used if several widget nodes will share the same params)

    <div class="wow_grid" id="mygrid" wow_params="externalparams"> <!-- wow_params value is id of DOM node containing params -->
    </div>

    <div id="externalparams" class="wow_params">
       columns:3,
       headings:['Head1','Head2','Head3']
    </div>


*/


Object.extend(Element.Methods, {

    wowparams: function(element,sType) {

        if (! sType) { sType = 'obj'; }

        var sParams = '';

        var param_attr = 'wow_params';

        // Check if params attribute contains dom node reference to "real" config node

            if (element.readAttribute(param_attr)) {

                sParams = element.readAttribute(param_attr);

                var aParts = sParams.split(':');

                if (aParts.length <= 1) {
                  // Params attribute only contains DOM id of node containing params
                  if ($(sParams)) { sParams = $(sParams).innerHTML; }
                }

            }

        // If we found no params attribute, find first child element with class name matching param_attr

          if (sParams==='') {

              var oDOM = element.select('.' + param_attr)[0];

              if (oDOM) {
                  sParams = oDOM.innerHTML;
                  //oDOM.remove();
              }

          } // end of processing of params node


        var oParams = {};

        // Empty config (or not present)?

            if (sParams==='') { return oParams; }

        // Raw config?

            if (sType == 'raw') {
                return sParams;
            }

        // Config object


            if (sParams.substr(0,1) != '{') {
                sParams = '{' + sParams + '}';
            }

            try {
                var sEval = 'oParams = eval(' + sParams + ');';
                eval(sEval);
            }
            catch(err) {
                var msg = 'Error in params string:' + sParams;
                oParams = {error:msg,err:err};
            }

            return oParams;

     } // End of element extension "getparams"
});

Element.addMethods();

if (typeof(Ext) != 'undefined') {

  Ext.override(Ext.Element, {
    wowparams : function() {
        var sType = typeof(this.dom);
        if (! sType) { sType = 'obj'; }

        var sParams = '';

        var param_attr = 'wow_params';

        // Check if params attribute contains dom node reference to "real" config node

            if ($(this.dom).readAttribute(param_attr)) {

                sParams = $(this.dom).readAttribute(param_attr);

                var aParts = sParams.split(':');

                if (aParts.length <= 1) {
                  // Params attribute only contains DOM id of node containing params
                  if ($(sParams)) { sParams = $(sParams).innerHTML; }
                }

            }

        // If we found no params attribute, find first child element with class name matching param_attr

          if (sParams==='') {

              var oDOM = this.select('.' + param_attr)[0];

              if (oDOM) {
                  sParams = oDOM.dom.innerHTML;
                  //oDOM.remove();
              }

          } // end of processing of params node


        var oParams = {};

        // Empty config (or not present)?

            if (sParams==='') { return oParams; }

        // Raw config?

            if (sType == 'raw') {
                return sParams;
            }

        // Config object


            if (sParams.substr(0,1) != '{') {
                sParams = '{' + sParams + '}';
            }

            try {
                var sEval = 'oParams = eval(' + sParams + ');';
                eval(sEval);
            }
            catch(err) {
                var msg = 'Error in params string:' + sParams;
                oParams = {error:msg,err:err};
            }

            return oParams;

    }

});

}


var WO_timer = {};

var WO = new function() {

  if (! WO_CONFIG_URL) {
    alert("WO_CONFIG_URL not defined - WO singleton cannot be instantiated");
    return undefined;
  }
  var oThis = this;

  // Get config values using a synchronous ajax call

  var rnd=Math.floor(Math.random()*99999999);

  var sURL = WO_CONFIG_URL + '&debug=off&rnd=' + rnd;

  var bOK = false;
  var oConfig;

  var ar = new Ajax.Request(sURL,{
    method : 'get',
    asynchronous: false,
    evalJS: true,
    onSuccess : function(resp) {
        try {
            oConfig = resp.responseText.evalJSON();
            bOK = true;
        }
        catch(err) {
        }
    }
  });

  if (! bOK) {
    alert("Could not fetch config info for WO object - instantiation fails");
    return undefined;
  }

  WO_timer.config_ok = new Date();

  if (typeof(WO_START) == 'undefined') {
    WO_START = new Date();
  }

  WO_timer.start = WO_START;

  if (typeof(window.google) == 'undefined' || typeof(google.gears)=='undefined') {
    this.googlegears = 0;
  }
  else{
    this.googlegears = 1;
  }

  this.freetext_store = oConfig.freetext;

  this.freetext = function(sKey) {
    var fstring = (WO.freetext_store) ? WO.freetext_store[sKey] : sKey;
    if (typeof(fstring) != 'string') { fstring = sKey; }
    if (fstring.length < 1) { fstring = sKey; }
    return fstring;
  };

  //this.interface = oConfig.interface;
  this.param = oConfig.param;
  this.setup = oConfig.setup;
  this.shopinfo = oConfig.shopinfo;

  this.script = oConfig.script;

  this.session = oConfig.session;

  this.d_application = oConfig.d_application;

  this.store = {};

  this.widget = {};
  this.widgets = {};

  if (typeof(oConfig.d_session) == 'undefined') {
    oConfig.d_session = {};
  }

  if (typeof(oConfig.d_session.wo_console_active) == 'undefined') {
    oConfig.d_session.wo_console_active = 0;
  }

  if (typeof(oConfig.d_session.wo_console_hidden) == 'undefined') {
    oConfig.d_session.wo_console_hidden = 0;
  }

  this.console = new WO_console(oConfig.d_session.wo_console_active,oConfig.d_session.wo_console_hidden);

    // d_session object

        this.d_session = new function() {

            // Initialize store

                this.store = oConfig.d_session;

            // Get value

                this.get = function(sKey,bAjax) {

                    if (typeof(bAjax) == 'undefined') {
                        bAjax = true;
                    }

                    if (bAjax) {
                        var sURL = WO.script.current + 'func=_d_common.get_value&obj=d_session&key=' + sKey + '&debug=off&output=json';
                        var ar2 = new Ajax.Request(sURL,{
                            asynchronous:false,
                            onSuccess : function(resp) {
                                var oRes = resp.responseText.evalJSON();
                                WO.d_session.store[sKey] = oRes;
                            }
                        });
                    }

                    if (! this.store[sKey]) {
                        return undefined;
                    }

                    return this.store[sKey];

                }; // End of method d_session.get

            // Set value

                this.set = function(sKey,sValue,bAsync) {

                    if (typeof(bAsync) == 'undefined') {
                        bAsync = false;
                    }

                    var vValue = sValue;

                    var sType = typeof(sValue);

                    if (sType.toLowerCase() == 'object') { sValue = Object.toJSON(sValue); }

                    if (Object.isArray(sValue)) { sValue = sValue.toJSON(); }

                    sType = typeof(sValue);

                    if (sType.toLowerCase() != 'string') {

                        try {
                            sValue = sValue.toJSON();
                        }
                        catch(err) {
                            sValue = '';
                        }
                    }

                    sType = typeof(sValue);

                    if (sType.toLowerCase() == 'string') {

                        var sURL = WO.script.current + 'func=_d_common.set_value&obj=d_session&key=' + sKey + '&value=' + sValue;
                        if (sValue.isJSON()) { sURL = sURL + '&json=1'; }

                        var bOK = 0;

                        var ar3 = new Ajax.Request(sURL,{
                            asynchronous:bAsync,
                            onSuccess: function(resp) {
                                if(parseInt(resp.responseText,10)==1) { bOK = 1; }
                            }
                        });
                    }

                    if (bOK==1 || bAsync === false) {
                      this.store[sKey] = vValue;
                    }

                    return bOK;

                }; // End of method d_session.set

            this.unset = function(sKey,bAsync) {

                if (typeof(bAsync) == 'undefined') {
                    bAsync = false;
                }

                var bOK = 0;

                var sURL = WO.script.current + 'func=_d_common.unset_value&obj=d_session&key=' + sKey;

                var ar4 = new Ajax.Request(sURL,{
                    asynchronous:bAsync,
                    onSuccess: function(resp) {
                        if(parseInt(resp.responseText,10)==1) { bOK = 1; }
                    }
                });

                if (bOK==1 || bAsync===false) {
                    delete this.store[sKey];
                }

                return bOK;

            }; // End of unset method for d_session

        }; // End of function for d_session object

    // User object

        this.d_user = new function() {

            // Initialize store

                this.store = oConfig.d_user;

                var d_user = this;

            // Get value

                this.get = function(sKey,bAjax) {

                    if (typeof(bAjax) == 'undefined') {
                        bAjax = true;
                    }

                    if (bAjax===true) {
                        var sURL = WO.script.current + 'func=_d_common.get_value&obj=d_user&key=' + sKey + '&debug=off&output=json';
                        var ar5 = new Ajax.Request(sURL,{
                            asynchronous:false,
                            onSuccess : function(resp) {
                                var oRes = resp.responseText.evalJSON();
                                WO.d_user.store[sKey] = oRes;
                            }
                        });
                    }

                    if (typeof(WO.d_user.store[sKey]) == 'undefined') {
                        return undefined;
                    }

                    return WO.d_user.store[sKey];

                }; // End of method d_user.get

            // Set value

                this.set = function(sKey,sValue,bAsync) {

                    if (typeof(bAsync) == 'undefined') {
                        bAsync = false;
                    }

                    var vValue = sValue;

                    var sType = typeof(sValue);

                    if (sType.toLowerCase() == 'object') { sValue = Object.toJSON(sValue); }

                    if (Object.isArray(sValue)) { sValue = sValue.toJSON(); }

                    sType = typeof(sValue);

                    if (sType.toLowerCase() != 'string') {

                        try {
                            sValue = sValue.toJSON();
                        }
                        catch(err) {
                            sValue = '';
                        }
                    }

                    sType = typeof(sValue);

                    if (sType.toLowerCase() == 'string') {

                        var sURL = WO.script.current + 'func=_d_common.set_value&obj=d_user&key=' + sKey + '&value=' + sValue;
                        if (sValue.isJSON()) { sURL = sURL + '&json=1'; }

                        var bOK = 0;

                        var ar6 = new Ajax.Request(sURL,{
                            asynchronous:bAsync,
                            onSuccess: function(resp) {
                                if(parseInt(resp.responseText,10)==1) { bOK = 1; }
                            }
                        });
                    }

                    if (bOK==1 || bAsync === false) {
                      this.store[sKey] = vValue;
                    }

                    return bOK;

                }; // End of method d_user.set

            this.unset = function(sKey,bAsync) {

                if (typeof(bAsync) == 'undefined') {
                    bAsync = false;
                }

                var bOK = 0;

                var sURL = WO.script.current + 'func=_d_common.unset_value&obj=d_user&key=' + sKey;

                var ar7 = new Ajax.Request(sURL,{
                    asynchronous:bAsync,
                    onSuccess: function(resp) {
                        if(parseInt(resp.responseText,10)==1) { bOK = 1; }
                    }
                });

                if (bOK==1 || bAsync===false) {
                    delete this.store[sKey];
                }

                return bOK;

            }; // End of unset method for d_user

        }; // End of function for d_user object

        //// TOINT //////////////////////////////////////////////////////////

        /*
           Function: WO.toint

              Function for converting string to int.

           Returns:

              integer or undef

           Example:

              var sString = 'product_131';
              var pid = WO.toint(sString);

        */
        
        this.toint = function(sVal) {
          
          sVal = sVal.replace(/[^0-9]/g, ''); 
          var vInt = parseInt(sVal);
      
          if (isNaN(vInt)) { return undefined; }
          
          return vInt;

          
        }

        //// AUTOID //////////////////////////////////////////////////////////

        /*
           Function: WO.autoid

              Function for creating a unique identifier.

           Returns:

              Unique id

           Example:

              var my_unique_id = WO.autoid();

        */
          this.autoid = function () {
            var sID = undefined;
            if (typeof(Ext) != 'undefined') {
                sID = Ext.id();
                return sID;
            }

            sID = Math.floor(Math.random() * 999999999);

            sID = sID + '';

            return sID;

          };

        //// GUID //////////////////////////////////////////////////////////

        /*
           Function: WO.guid

              Function for creating a globally unique identifier.

           Returns:

              Globally unique id

           Example:

              var my_guid = WO.guid();

        */
          this.guid = function () {

              // http://www.ietf.org/rfc/rfc4122.txt

              var s = [];
              var hexDigits = "0123456789ABCDEF";

              for (var i = 0; i < 32; i++) {
                s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
              }

              s[12] = "4";

              // bits 12-15 of the time_hi_and_version field to 0010

              s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);
              // bits 6-7 of the clock_seq_hi_and_reserved to 01

              var uuid = s.join("");

              return uuid;

          }




        //// DECODE_ENTITY //////////////////////////////////////////////////////////

        /*
           Function: WO.decode_entity

              Function for decoding HTML entitities.

           Returns:

              Decoded string

           Example:

              sDecoded = WO.decode_entity('Test &#45;');

        */

          this.decode_entity = function(t){
          //remove carriage returns
            t = t.replace(new RegExp("\\=\r\n","gim"), "");
          //replace urlencoded values
            t = unescape(t);
          //replacement values
            var thechrs = new Array(
              ' ','!','"','#','$','%','&',"'",'(',')','*','+',',','-','.','/','0','1','2','3',
              '4','5','6','7','8','9',':',';','<','=','>','?','@','A','B','C','D','E','F','G',
              'H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[',
              '\\',']','^','_','`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
              'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~',' ','c','u','e','a',
              'a','a','a','c','e','e','e','i','i','i','a','a','e','ae','ae','o','o','o','u','u',
              'y','u','u','o','l','0','x','f','a','i','o','u','n','n','*','O','?','r','_','?',
              '?','!','<','>','_','_','_','|','|','a','a','a','c','|','|','+','+','c','y','+',
              '+','-','-','+','-','+','a','a','+','+','-','-','|','-','+','.','.','d','e','e',
              'e','i','i','i','i','+','+','_','_','|','i','_','o','o','o','o','o','o','u','p',
              'p','u','u','u','y','y','_',"'",'-','?','_','?','?','S','÷','¸','°','¨','·','¹',
              '³','²','_',' ');
          //replace js numeric array values
            var l = 32;
            for (l = 32; l < 256; l++){
              t = t.replace(new RegExp("\\[" + l + ",","gim"),"[" + thechrs[l-32] + ",");
              t = t.replace(new RegExp("\\[" + l + ",","gim"),"[" + thechrs[l-32] + ",");
            }
            for (l = 32; l < 256; l++){
              t = t.replace(new RegExp("," + l + "\\]","gim"),"," + thechrs[l-32] + "]");
              t = t.replace(new RegExp("," + l + "\\]","gim"),"," + thechrs[l-32] + "]");
            }
            for (l = 32; l < 256; l++){
              t = t.replace(new RegExp("," + l + ",","gim"),"," + thechrs[l-32] + ",");
              t = t.replace(new RegExp("," + l + ",","gim"),"," + thechrs[l-32] + ",");
            }
            ta = t;
            t = t.replace(new RegExp("(\\[[^\\]]+)\\,([^\\]]+\\])","gim"), "$1$2");
            while(ta !== t){
              ta = t;
              t = t.replace(new RegExp("(\\[[^\\]]+)\\,([^\\]]+\\])","gim"), "$1$2");
            }
          //replace entities
            var l = 32;
            for (l = 32; l < 100; l++){
              t = t.replace(new RegExp("&#" + l + ";","gim"),thechrs[l-32]);
              t = t.replace(new RegExp("&#0" + l + ";","gim"),thechrs[l-32]);
              t = t.replace(new RegExp("&#00" + l + ";","gim"),thechrs[l-32]);
            }
            var l = 100;
            for (l = 100; l < 256; l++){
              t = t.replace(new RegExp("&#" + l + ";","gim"),thechrs[l-32]);
              t = t.replace(new RegExp("&#0" + l + ";","gim"),thechrs[l-32]);
            }
            return t;
          }

     // store_set - Set value in WO.store

        this.store_set = function(sKey,vValue,sNamespace) {

          if (! sNamespace) {
            WO.store[sKey] = vValue;
          }

          else {
            WO.store_namespace(sNamespace);
            eval('var oStore=WO.store.' + sNamespace + ';');
            oStore[sKey] = vValue;
          }

        }

     // store_sync - fetch values from hidden input fields

        this.store_sync = function(oElem) {

            if (! Object.isElement(oElem)) {
                oElem = document.body;
            }

            oElem = $(oElem);

            var aElems = oElem.select('input.WO_store');

            var aFailed = [];

            aElems.each(function(oElem) {

                var sName = oElem.readAttribute('name');
                var sValue = oElem.readAttribute('value');

                if (! sValue) { sValue = ''; }

                var orig_value = sValue;

                if (sName) {

                    if (sValue.indexOf('{') != -1) {

                        try {
                            sValue = sValue.evalJSON();
                         }
                         catch(err) {
                            aFailed.push(sName);
                            sValue = orig_value;
                         }

                    }

                     var sNamespace = oElem.readAttribute('namespace');

                     var oStore = WO.store;

                     if (sNamespace) {

                        aNSparts = sNamespace.split('.');

                        aNSparts.each(function(sPart){

                            if (! sPart.length) { return; }

                            if (! oStore[sPart]) {
                                oStore[sPart] = {};
                            }

                            oStore = oStore[sPart];

                        });

                     }

                     oStore[sName] = sValue;

                }


            });

            if (aFailed.length) {
                return aFailed.join(',');
            }

            return 1;

        };

        this.store_namespace = function(sNamespace) {

            var oStore = WO.store;

            aNSparts = sNamespace.split('.');

            var NSparts_final = [];

            aNSparts.each(function(sPart){

                if (! sPart.length) { return; }

                if (! oStore[sPart]) {
                    oStore[sPart] = {};
                }

                oStore = oStore[sPart];
                NSparts_final.push(sPart);

            });

            var sNS_final = NSparts_final.join('.');

            var result = eval('var test = WO.store.' + sNS_final);

            //alert("Added namespace:" + sNS_final);

            if (! result) { return 0; }

            return 1;

        };

        this.main_init = function(e) {

            WO.init();
            //document.stopObserving('dom:loaded',WO.main_init);

            if (typeof(WO_INIT_AFTER) == 'function') {
              try { WO_INIT_AFTER(document.body); } catch(err) {}
            }

            if (typeof(this.console) != 'undefined') {
                this.console.log("WO main_init end");
            }
        };

        this.init = function(oElem) {


            if (typeof(WO_INIT_BEFORE) == 'function') {
              try { WO_INIT_BEFORE(oElem); } catch(err) {}
            }

            if (! oElem) {  oElem = document.body; }
            oElem = $(oElem);

            /*if (typeof(oElem.id) != 'undefined') {
              WO.console.log("WO.init with elem " + oElem.id);
            } */

            //if (this.console) { this.console.init(); }

            // Pick up WO_store elements and populate WO_store accordingly

                this.store_sync(oElem);

            // Find and initialize widgets

                this.widgets_create(oElem);

            if (typeof(WO_INIT_AFTER) == 'function') {
              try { WO_INIT_AFTER(oElem); } catch(err) {}
            }

        };

        this.widgets_create = function(oElem) {


             // Find all elements with a class name starting with "wow_" and call the constructor for each widget
             //
             // widget constructor example: grid = new WO.widget.grid(oElem), where oElem is the DOM node of the widget
             //
             // Widget instances are stored in WO.widgets[sName], where sName is the id of the widget's DOM node,
             // or the widget name (e.g. "grid") if the DOM node has no id

             if (! oElem) { oElem = document.body;}
             oElem = $(oElem);

             // Find widgets - all elements with class attribute set and class containing the string "wow_"

              if (typeof(Ext) != 'undefined') {
                var wow_elems = Ext.DomQuery.select('*[class^=wow_]',oElem);
              }
              else {
                var wow_elems = [];
              }

              wow_elems.each(function(widget_elem){

                widget_elem = $(widget_elem);

                var sClass = widget_elem.readAttribute('class');

                // Find widget name (e.g. "wow_grid") and widget id

                    var widget_name = '';

                    if (sClass === null) {
                        sClass = widget_elem.getAttribute('class'); // IE 8 fix
                    }

                    var aParts = sClass.split('wow_');

                    if (aParts.length >=2 ) {
                        var aParts2 = aParts[1].split(' ');
                        widget_name = aParts2[0];
                    }

                    widget_name = widget_name.toLowerCase();

                    if (widget_name.length < 1) { return; }
                    if (widget_name == 'params') { return; } // "wow_params" is not a widget
                    if (widget_name == 'eval') { return; } // "wow_eval" is not a widget

                    var widget_id = undefined;
                    if (widget_elem.id) {
                      widget_id = widget_elem.id;
                    }
                    else {
                      widget_id = widget_name;
                    }

                 // Initialize widget

                     var sInit = "WO.widgets['" + widget_id + "'] = new WO.widget." + widget_name + "(widget_elem);";

                     try {

                        eval(sInit);

                      }

                      catch(err) {

                        // Catch error for undefined widgets

                        var msg = 'Code error in init of <b>' + widget_name  + '</b> widget<br/>(' + err.name + ' - ' + err.description + ' ' + err.message + ')';
                        if (WO.console) {
                            WO.console.log(msg,"error");
                            WO.console.dump(err);
                        }
                        else {
                            alert(msg);
                        }

                      }

              });

        }; // End of WO.widgets_create

        this.ajax = function(options) {

            if (typeof(options.params) != 'undefined') {
            
              if (typeof(options.params.output) == 'undefined') {
                options.params.output = 'json';
              }  
              
            }
            
            if (typeof(options.url) == 'undefined') {
              options.url = WO.script.current;
            }  

            Ext.Ajax.request(options);
            
        }; // End of WO.ajax

        this.ajaxreq = function(sURL,options) {

            new Ajax.Request(sURL,options);
            
        }; // End of WO.ajaxreq

    this.timelog = new function() {
        this.log = new Array();
        this.starttime = new Date();
        this.track = {};

        this.reset = function () {
            this.starttime = new Date();
        };

        this.start = function (id, msg) {
            var mydate = new Date();
            this.track[id] = {id : id, time : mydate, durationFromStart : this.getDurationFromStart(mydate), msg : msg};
        };

        this.stop = function (id) {
            var mydate = new Date();
            if (typeof(this.track[id]) != 'undefined') {
                this.track[id].stop = mydate;
                this.track[id].duration = this.getDuration(this.track[id].time, this.track[id].stop);
                this.track[id].durationFromStartStop = this.getDurationFromStart(this.track[id].stop);

                this.add(this.track[id]);
                delete this.track[id];
            }
        };

        this.set = function (msg) {
            var mydate = new Date();
            this.add({msg : msg, time : mydate, durationFromStart : this.getDurationFromStart(mydate)});
        };

        this.setMarker = function (msg) {
            var mydate = new Date();
            var mymarker = {msg : msg, time : mydate, marker : true, durationFromStart : this.getDurationFromStart(mydate)};
            if (typeof(this.marker) != 'undefined' && typeof(this.marker.time) != 'undefined') {
                mymarker.duration = this.getDuration(this.marker.time, mymarker.time);
            }
            this.marker = mymarker;
            this.add(mymarker);
        };

        this.getLog = function () {
            return this.log;
        };

        this.resetLog = function () {
            delete this.log;
            this.log = new Array();
        };

        this.getDurationFromStart = function (mydate) {
            return Math.ceil(mydate.getTime() - this.starttime.getTime());
        };

        this.getDuration = function (firstdate, lastdate) {
            return Math.ceil(lastdate.getTime() - firstdate.getTime());
        };

        this.add = function (rec) {
            this.log.push(rec);
        };
    };
    
    this.undef_default = function(vVariable,value_if_undef) {
      
      if (typeof(vVariable)=='undefined') {
        return value_if_undef;
      }
      
      return vVariable;
      
    }


}; // End of WO singleton definition


/*

    Class: WO_console

    Properties:

        active (set from WO.d_session.wo_console_active):

                0 - console is not shown
                1 - console is shown

        hidden  (set from WO.d_session.wo_console_active):

                0 - console is maximized (non-hidden)
                1 - if console is active, it is shown minimized

        start - JavaScript date - set by constructor and clear method

    Methods:

        WO_console : constructor

        init()  - Initializes the HTML elements used for the constructor

        log(strMessage,strClass)

            Logs the message strMessage to the console DIV.
            If strClass is defined, the div for the message will get the class attribute set to strClass
            If strClass = "error", the div will get style="background-color:pink" added as well

*/

function WO_console(iActive,iHidden) {

    this.active = parseInt(iActive,10);
    this.hidden = parseInt(iHidden,10);

    this.start = new Date();

    this.width = 400;
    this.height = 650;

    this.init = function() {

            if (! $('wo_console')) {

                if (document.body) {

                    this.elem = new Element('div');
                    this.elem.id='wo_console';

                    var oStyle =  {
                        position:'absolute',
                        top:'0px',
                        right:'0px',
                        width:this.width + 'px',
                        border:'1px solid #999',
                        background:'#eee',
                        padding:'10px',
                        overflow:'auto',

                        font: 'normal 10px verdana,sans-serif'
                    };

                    this.elem.setStyle(oStyle);

                    document.body.appendChild(this.elem);

                    this.elem.innerHTML = '<a id="wo_console_control" href="#" onclick="WO.console.toggle();return false" target="null">Hide &gt;&gt;</a>&nbsp;&nbsp;';
                    this.elem.innerHTML = this.elem.innerHTML + '<a id="wo_console_clear" href="#" onclick="WO.console.clear();return false" target="null">Clear</a>&nbsp;&nbsp;&nbsp;&nbsp;';
                    this.elem.innerHTML = this.elem.innerHTML + '<a id="wo_console_close" href="#" onclick="WO.console.close();return false" target="null">Close</a><br/>';

                    this.elem_log = new Element('div');
                    this.elem_log.id='wo_console_log';

                    //this.elem_log.setStyle({'font-size':'10px','font-family':'verdana,courier,monospace'});

                    this.elem.appendChild(this.elem_log);

                    if (! this.active) {
                      this.elem.setStyle({'display':'none'});
                    }

                    else {
                      this.elem.setStyle({'display':'inline'});
                    }

                    this.elem_ctrl = $('wo_console_control');
                    this.elem_log = $('wo_console_log');

                    //var log_start = '';

                    //this.elem_log.innerHTML = log_start;

                   if (this.hidden==1) {
                    this.hide(1);
                   }

               } // End of if(document.body)

            }

    }; // End of WO_console.init

    this.show = function() {

        this.hidden = 0;
        this.active = 1;

        this.elem.setStyle({'display':'inline','width':this.width + 'px','height':this.height + 'px'});

        this.elem_ctrl.innerHTML = '&gt;&gt;Hide';
        this.elem_ctrl.writeAttribute('title','Hide');

        $('wo_console_close').setStyle({'display':'inline'});
        $('wo_console_clear').setStyle({'display':'inline'});
        this.elem_log.setStyle({'display':'inline'});

    };

    this.toggle = function() {

        if (this.hidden ==1) {
            this.show();
            WO.d_session.set('wo_console_hidden',0);
        }
        else {
            this.hide();
        }

    };

    this.hide = function(bNoSave) {

        this.hidden = 1;

        this.elem_ctrl.innerHTML = '&lt;&lt;';
        this.elem_ctrl.writeAttribute('title','Show');

        this.elem.setStyle({'width':'50px','overflow':'hidden'});

        $('wo_console_close').setStyle({'display':'none'});
        $('wo_console_clear').setStyle({'display':'none'});
        this.elem_log.setStyle({'display':'none'});

        if (! bNoSave) {
            bNoSave = 0;
        }

        if (bNoSave != 1) {
            WO.d_session.set('wo_console_hidden',1);
        }

    };

    this.close = function() {

        this.active = 0;
        this.elem.setStyle({'display':'none'});

        var success = WO.d_session.set('wo_console_active','0');

    };

  this.clear = function() {

    this.elem_log.innerHTML = '';

  };

    this.log = function(strMessage,strClass) {
    
          if (this.active) { this.init(); }

          var orig_message = strMessage;

          // Create datetime string

              var now = new Date();

              var sHours = now.getHours() + '';
              if (sHours.length < 2) { sHours = '0' + sHours; }

              var sMins = now.getMinutes() + '';
              if (sMins.length < 2) { sMins = '0' + sMins; }

              var sSecs = now.getSeconds() + '';
              if (sSecs.length < 2) { sSecs = '0' + sSecs; }

              var ds = sHours + ':' + sMins + ':' + sSecs;

          // Log the message to the HTML log element

              if (! $(this.elem_log)) {
                this.init();
              }

              if ($(this.elem_log)) {

                // Display timing information

                if (WO_timer.start) {

                    now = WO_timer.start;

                    sHours = now.getHours() + '';
                    if (sHours.length < 2) { sHours = '0' + sHours; }

                    sMins = now.getMinutes() + '';
                    if (sMins.length < 2) { sMins = '0' + sMins; }

                    sSecs = now.getSeconds() + '';
                    if (sSecs.length < 2) { sSecs = '0' + sSecs; }

                    ds = sHours + ':' + sMins + ':' + sSecs;

                    var sLog = '<div><b>' + ds +  '</b> WO_START</div>';

                    this.elem_log.innerHTML = this.elem_log.innerHTML + sLog;

                    WO_timer.start = undefined;

                }

                if (WO_timer.config_ok) {

                    now = WO_timer.config_ok;

                    sHours = now.getHours() + '';
                    if (sHours.length < 2) { sHours = '0' + sHours; }

                    sMins = now.getMinutes() + '';
                    if (sMins.length < 2) { sMins = '0' + sMins; }

                    sSecs = now.getSeconds() + '';
                    if (sSecs.length < 2) { sSecs = '0' + sSecs; }

                    ds = sHours + ':' + sMins + ':' + sSecs;

                    sLog = '<div><b>' + ds +  '</b> WO config ok</div>';

                    this.elem_log.innerHTML = this.elem_log.innerHTML + sLog;

                    WO_timer.config_ok = undefined;

                }


                if (strClass=='inspect') {
                  strMessage = '<textarea style="font-size:10px;font-family:verdana;width:100%;height:100px;">' + strMessage + '</textarea>';
                }         

                strMessage = '<b>' + ds + '</b> ' + strMessage;

                var sDiv = '<div>';

                if (strClass) {
                  sDiv = '<div class="' + strClass + '">';
                }

                if (strClass == 'error') {
                  sDiv = '<div class="' + strClass + '" style="background-color:pink">';
                }


                this.elem_log.innerHTML = this.elem_log.innerHTML + sDiv + strMessage + '</div>';

              }

              else {

                // Log the message to the console object(if it exists)

                  if (console) {
                    console.log("WO.console message (" + ds + '): ' + orig_message);
                  }
                  else {
                    alert("WO.console alert:\n\n" + orig_message);
                  }

              }

    };

    this.dump = function(sTitle,oObj) {

        if (! oObj) {
            oObj = sTitle;
            sTitle = '';
        }

        var aKeys=Object.keys(oObj).sort();
         var sRes = '';
         aKeys.each(function(sKey){
            sRes= sRes + '<tr><td style="padding:2px;"><b>' + sKey + '</b></td><td style="padding:2px;">' + oObj[sKey] + '&nbsp;</td></tr>';
        });

        sRes = '<table class="values" border="1" cellpadding="5" cellspacing="0" style="background-color:white">' + sRes + "</table>";

        if (sTitle.length) {
          sRes = sTitle + sRes;
        }

        this.log(sRes);

    };

    if (this.active) {
        this.init();
    }

}


// If WO_MAIN_INIT function is defined, use it as overridden version of WO.main_init

    if (typeof(WO_MAIN_INIT) == 'function') {
        document.observe('dom:loaded',WO_MAIN_INIT);
    }
    else {
        document.observe('dom:loaded',WO.main_init);
    }
