// improve AlwaysVisibleControl ;)
AjaxControlToolkit.AlwaysVisibleControlBehavior.prototype.get_MinOffsetFromPageBottom = function()
{
    return this._minOffsetFromPageBottom;
}

AjaxControlToolkit.AlwaysVisibleControlBehavior.prototype.set_MinOffsetFromPageBottom = function(value)
{
    this._minOffsetFromPageBottom = value;
}


AjaxControlToolkit.AlwaysVisibleControlBehavior.prototype._reposition = function(eventObject) 
{
    var element = this.get_element();
    if (!element) return;

    this.raiseRepositioning(Sys.EventArgs.Empty);

    var x = 0;
    var y = 0;
    var scrollHeight = 0; 

    // Compute the initial offset if we're animating
    if (this._animate) {
        if (document.documentElement && document.documentElement.scrollTop) {
            x = document.documentElement.scrollLeft;
            y = document.documentElement.scrollTop;
            scrollHeight = document.documentElement.scrollHeight; 
        } else {
            x = document.body.scrollLeft;
            y = document.body.scrollTop;
            scrollHeight = document.body.scrollHeight; 
        }
    }

    // Compute the width and height of the client
    var clientBounds = $common.getClientBounds();
    var width = clientBounds.width;
    var height = clientBounds.height;

    // Compute the horizontal coordinate
    switch (this._horizontalSide) {
        case AjaxControlToolkit.HorizontalSide.Center :
            x = Math.max(0, Math.floor(x + width / 2.0 - element.offsetWidth / 2.0 - this._horizontalOffset));
            break;
        case AjaxControlToolkit.HorizontalSide.Right :
            x = Math.max(0, x + width - element.offsetWidth - this._horizontalOffset);
            break;
        case AjaxControlToolkit.HorizontalSide.Left :
        default :
            x += this._horizontalOffset;
            break;
    }            

    // Compute the vertical coordinate
    switch (this._verticalSide) {
        case AjaxControlToolkit.VerticalSide.Middle :
            y = Math.max(0, Math.floor(y + height / 2.0 - element.offsetHeight / 2.0 - this._verticalOffset));
            break;
        case AjaxControlToolkit.VerticalSide.Bottom :
            y = Math.max(0, y + height - element.offsetHeight - this._verticalOffset);
            break;
        case AjaxControlToolkit.VerticalSide.Top :
        default :
            y += this._verticalOffset;
            break;
    }

    if (this._minOffsetFromPageBottom && y > (scrollHeight - this._minOffsetFromPageBottom))
    {
        y = scrollHeight - this._minOffsetFromPageBottom;
    }

    // Move the element to its new position
    if (this._animate && this._animation) {
        this._animation.stop();
        this._animation.set_horizontal(x);
        this._animation.set_vertical(y);
        this._animation.play();
    } else {
        element.style.left = x + 'px';
        element.style.top = y + 'px';
    }

    this.raiseRepositioned(Sys.EventArgs.Empty);
}

//function ConfHelper(){} 
ConfHelper = {};
ConfHelper.prototype = {};
ConfHelper.initPrototype = function (tplParams, cl, tplName)
{
    // this function will init prototype of a given class
    // with DOM objects applicable to that class 
    // params:
    // tplParams - parameters used to initialize template 
    // cl - class whose prototype is to be extended
    // tplName - starting part of the parameters which should
    //           should be processed
    var tplNameLength = tplName.length;
    var elName;

    for (var name in tplParams)
    {
        var parentAppendix = '_PARENT';
        if (name.substr(0, tplNameLength) === tplName
                && name.substr(name.length - 2, 2).toLowerCase() === 'id')
        {
            elName = "tpl_" + name.substring(tplNameLength, name.length - 2).toLowerCase() + "el";
            var el = $get(tplParams[name]);

            cl.prototype[elName]= el;

            // set parent if possible
            var par = $get(tplParams[name] + parentAppendix);
            if (!par && el)
                par = el.parentNode; 

            if (par && !par.id)
                par.id = name + parentAppendix;

            elParName = elName + parentAppendix.toLowerCase();
            cl.prototype[elParName] = par;
        }
    }
}

ConfHelper.createNewEl = function (pNode, tplEl, id)
{
    // this function will create new DOM element 
    // from tpl, will change its id and will put it under pNode 
    // params:
    // pNode - node to put new element under, if null then the same parent 
    //        as for template element is used
    // tplEl - template DOM element... copy will be created 
    // id - id of the newly created DOM element 
    // return: newly created DOM element 

    if (!tplEl)
        throw ("ConfHelper::createNewEl: template element not specified");

    if (!pNode)
        pNode = tplEl.parentNode;

    var newEl = tplEl.cloneNode(true);
    newEl.id = id;

    //hide new element 
    ConfHelper.setVisible(newEl, false);

    // attach it to parent 
    pNode.appendChild(newEl);

    return newEl;
}

ConfHelper.findEl = function (tplEl, parentEl, defEl)
{
    // this function will try to find DOM element which has
    // the same id as tplEl. If tplEl not specified then defEl returned
    // params:
    // tplEl - template element which has the same id as the
    //         element we are looking for
    // parentEl - parentNode to start search from 
    // defEl - element to be returned if tplEl not specified
    // return: found element or defEl

    if (!tplEl && !defEl)
        throw ("ConfHelper::findEl : both template element and default one not specified");

    if (!tplEl)
        return defEl;

    var tplID = tplEl.id;
    var newEl = $get(tplID, parentEl);

    if (!newEl)
        throw ("Could not find new element[" + tplID + "]");

    return newEl;
}

ConfHelper.findAndChange = function (tplEl, parentEl, newID, defEl)
{
    // this function will try to find DOM element which has
    // the same id as tplEl, and then it will change its id
    // to newID. If tplEl not specified then defEl returned
    // params:
    // tplEl - template element which has the same id as the
    //         element we are looking for
    // parentEl - parentNode to start search from 
    // newID - id to be assigned to found element
    // defEl - element to be returned if tplEl not specified
    // return: found element or defEl

    if (!tplEl && !defEl)
        throw ("ConfHelper::findAndChange: both template element and default one not specified");

    if (!tplEl)
        return defEl;

    var tplID = tplEl.id;
    //tplEl.id = tplID + '_temporary_';
    var newEl = $get(tplID, parentEl);

    if (!newEl)
        throw ("Could not find new element[" + tplID + "]");

    newEl.id = newID;
    //tplEl.id = tplID;

    return newEl;
}

ConfHelper.removeEl = function (el)
{
    // this function will remove el from its parent 
    // params:
    // el - DOM element to be removed 

    if (!el)
        throw ("ConfHelper::removeEl: element not provided");

    el.parentNode.removeChild(el);

}

ConfHelper.removeAll = function (parentNode)
{
    // this function will remove all nodes from given parent 
    // params:
    // parentNode  - DOM element childrens to be removed from 

    if (!parentNode)
        throw ("ConfHelper::removeAll: parent node not provided");

    while(parentNode.lastChild)
        parentNode.removeChild(parentNode.lastChild);
}

ConfHelper.attachText = function (el, text)
{
    // this function will attach text node under DOM element
    // passed as argument
    // el - DOM element to which text node should be attached 
    // text - text with which text node should be initialized 

    if (!el)
        throw ("ConfHelper::attachText: DOM element not specified");

    var textNode = document.createTextNode(text);
    el.appendChild(textNode);
}

ConfHelper.setVisible = function (el, visible)
{
    // shows or hides DOM element 
    if (visible)
        el.style.display = '';
    else
        el.style.display = 'none';
}

ConfHelper.getVisible = function (el)
{
    return !(el.style.display === 'none') 
}

ConfHelper.sendAjax = function (type, id, text, callback, usePost)
{
    // this function will try to send request to server 
    // via Ajax
    // parameters:
    // type - request type 
    // id - id of the data to retrieve/save
    // text - text to send out
    // callback - function to be called when done 

    var link = ConfData.prototype.ajaxUrl;
    link = link + "&type=" + type;
    link = link + "&id=" + id;
    if (!usePost)
        link = link + "&text=" + text;

    var handler = function (executor, eventArgs)
    {
        if(executor.get_responseAvailable())
        {
            var resp = executor.get_responseData();
            callback(resp);
        }
        else
        {
            if (executor.get_timedOut())
                alert("Timed Out");
            else
                if (executor.get_aborted())
                    alert("Aborted");
        }
    }

    // Instantiate the WebRequest object.
    var wRequest =  new Sys.Net.WebRequest();

    // Set the request Url.
    wRequest.set_url(link);

    var verb;
    if (usePost)
        verb = "POST";
    else
        verb = "GET";

    // Set the request verb.
    wRequest.set_httpVerb(verb);

    if (usePost)
    {
        var body = text;
        wRequest.set_body(body);
        wRequest.get_headers()["Content-Length"] = body.length;
        wRequest.get_headers()["Content-Type"] = "text/html; charset=UTF-8";
    }

    // Set user's context
    //wRequest.set_userContext("user's context");

    // Set the web request completed event handler,
    // for processing return data.
    wRequest.add_completed(handler);


    // Execute the request.
    wRequest.invoke();
}

/* this class will only contain text definitions obtained
    from template and used by other configurator classes
*/
function ConfiguratorDefs()
{
}

ConfiguratorDefs.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, ConfiguratorDefs, 'DEFS_');

    // retrieve innerHTML from Def elements
    var value, text, nname;
    for (var name in ConfiguratorDefs.prototype)
    {
        if (name.substr(0, 4).toLowerCase() === 'tpl_' &&
            name.substr(name.length - 3, 3).toLowerCase() === '_el')
        {
            value = ConfiguratorDefs.prototype[name];
            text = value.innerHTML;

            // remove trailing "tpl_" and ending "_el"
            nname = name.substring(4, name.length - 3);

            ConfiguratorDefs.prototype[nname] = text;
        }
    }
}

function Asistant()
{
    this.parent = null;     // points to kategory
    this.el = null;         // Product DOM element

    this.shown_prods = [];
}

Asistant.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, Asistant, 'ASISTANT_');
}

Asistant.prototype =
{
    init : function (p, parent, deep)
    {
        // copy all properties from p
        for (var name in p)
        {
            this[name] = p[name];
        }
        
        this.parent = parent;
    },
    
    create : function (x_offset, y_offset)
    {
        this._createAsistant(x_offset, y_offset);
    },

    _createAsistant: function (x_offset, y_offset)
    {
        var el = this.tpl_el;
        ConfHelper.setVisible(el, true);
        var bounds = Sys.UI.DomElement.getBounds(el);
		 
        var offset = x_offset + bounds.width +440;


        var alwaysVisible = this.alwaysVisible = $create(AjaxControlToolkit.AlwaysVisibleControlBehavior, 
                                        {'VerticalSide': AjaxControlToolkit.VerticalSide.Bottom, 
                                        'HorizontalOffset' : offset,
                                        'VerticalOffset' : 25,
                                        'MinOffsetFromPageBottom' : 190,
                                        'useAnimation' : true }, 
                                        null, null, el);
        $addHandler(this.tpl_finish_el, 'click', Function.createDelegate(this.parent, this.parent.showSummary));
    },

    update: function (prods)
    {
        var shown_prods = this.shown_prods;

        // remove any unncecesary currently visible prods
        while (shown_prods.length > prods.length && shown_prods.length > 0)
        {
            var shown_prod = shown_prods[shown_prods.length - 1];

            var prod_el = shown_prod.prod_el;

            prod_el.parentNode.removeChild(prod_el);

            Array.removeAt(shown_prods, shown_prods.length - 1);
        }

        // update currently visible prods with the new ones
        var p = 0;
        for (p = 0; p < shown_prods.length && p < prods.length; ++p)
        {
            var shown_prod = shown_prods[p];
            var prod = prods[p];
            var name_el = shown_prod.prod_name_el; 

            ConfHelper.removeAll(name_el);
            ConfHelper.attachText(name_el, prod.getName());
        }


        // add new prods
        for (; p < prods.length; ++p)
        {
            var prod = prods[p];

            var prod_el = ConfHelper.createNewEl(this.tpl_prod_el_parent, this.tpl_prod_el, null);
            var name_el = ConfHelper.findAndChange(this.tpl_prod_name_el, prod_el, null, prod_el);
            
            ConfHelper.attachText(name_el, prod.getName());
            
            ConfHelper.setVisible(prod_el, true);

            var shown_prod = {};
            shown_prod.prod = prod;
            shown_prod.prod_el = prod_el;
            shown_prod.prod_name_el = name_el;
            shown_prods[shown_prods.length] = shown_prod;
        }

        // fill price
        var price = 0.0;
        for (p = 0; p < prods.length; ++p)
		{

            price = price + prods[p].getPrice();
			
		}

        var price_el = this.tpl_price_el;
		var price_netto_el = this.tpl_price_netto_el;

        ConfHelper.removeAll(price_el);
        ConfHelper.attachText(price_el, (price*1.23).toFixed(2) ); 

		ConfHelper.removeAll(price_netto_el);
        ConfHelper.attachText(price_netto_el, price.toFixed(2));
    }
}

function Product()
{
    this.parent = null;     // points to kategory
    this.el = null;         // Product DOM element
    this.name = null;       // product name
    this.long_name = null;  // product long name (to be displayed)
    this.producent = null;  // product producent 
    this.part_nr = null;    // product part number 
    this.photo = null;      // photo description
    this.type = null;       // product type(e.g. 'radio', 'text'...)
    this.radio_el = null;   // DOM of radio button
    this.show_on_summary = true;   // indicates if product should be showed on summary tab when selected 
    this.count = 0;         // number of products choosen
    this.pack_count = 0;    // number of products in a pack (e.g. when multiprocessor machine) 
    this.read_only = false; // indicates if product is read only... aplicable to checkboxes and textboxes
}

Product.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, Product, 'PROD_');
}

Product.prototype =
{
    init : function (p, parent, deep)
    {
        // copy all properties from p
        for (var name in p)
        {
            this[name] = p[name];
        }

        this.show_on_summary = this.show_on_summary === '1' ? true : false; 
        this.read_only = this.read_only === '1' ? true : false; 
        
        if (typeof(this.count) === 'string')
        {
            try
            {
                this.count = parseInt(this.count);
                if (this.count < 0)
                    this.count = 0;
            }
            catch(err)
            {
                this.count = 0;
            }
        }

        if (typeof(this.pack_count) === 'string')
        {
            try
            {
                this.pack_count = parseInt(this.pack_count);
                if (this.pack_count < 0)
                    this.pack_count = 0;
            }
            catch(err)
            {
                this.count = 0;
            }
        }

        this.parent = parent;
    },

    getConfigurator: function ()
    {
        var conf = null;
        var parent = this;
        while ((parent = parent.parent) && !(parent instanceof Configurator));

        return parent;
    },
    
    create : function (deep, replacedProd)
    {
		 

        this._createProd(replacedProd);
        this._createEditProd();
        this._createDelProd();
        this._createMoveProd();
        this._createPhoto();
        this._createType();
        this._createPrice();
    },

    _createProd : function (replacedProd)
    {
        var el_parent = this.parent.prod_el_parent;

        var el = this.el = ConfHelper.createNewEl(el_parent, this.tpl_el, null);
        if (replacedProd)
        {
            el_parent.replaceChild(el, replacedProd.el);
        }
        var name_el = ConfHelper.findAndChange(this.tpl_name_el, el, null, el);
        var name = this.long_name;
        if (!name)
            name = this.name;

		var type = this.parent.type;


        if (this.pack_count)
            name = this.pack_count + ' x ' + name;

		

        ConfHelper.attachText(name_el, name);

        // set part numer if exists in template
        if (this.tpl_part_nr_el)
        {
            var part_nr_el = ConfHelper.findAndChange(this.tpl_part_nr_el, el, null);
            var part_nr = this.part_nr;
            if (!part_nr)
                part_nr = '';
            ConfHelper.attachText(part_nr_el, part_nr);
        }

        ConfHelper.setVisible(el, true);

		if(this.el.rowIndex == 0)
		{
			name_el.className = 'konfig-name-first';
		}else
		{
			name_el.className = 'konfig-name';
		}

	     
   
    },

    _createEditProd: function ()
    {
        // will attach event listener to 'edit product' element if present
        if (this.tpl_edit_el)
        {
            var edit_el = ConfHelper.findAndChange(this.tpl_edit_el, this.el, null);
            $addHandler(edit_el, 'click', Function.createDelegate(this, this.editClicked));
        }
    },

    _createDelProd: function ()
    {
        // will attach event listener to 'delete product' element if present
        if (this.tpl_del_el)
        {
            var del_el = ConfHelper.findAndChange(this.tpl_del_el, this.el, null);
            $addHandler(del_el, 'click', Function.createDelegate(this, this.delClicked));
        }
    },

    _createMoveProd: function ()
    {
        // will attach event listener to UP/DOWN buttons if present
        if (this.tpl_move_up_el)
        {
            var move_up_el = ConfHelper.findAndChange(this.tpl_move_up_el, this.el, null);
            $addHandler(move_up_el, 'click', Function.createDelegate(this, this.moveUpClicked));
        }

        if (this.tpl_move_down_el)
        {
            var move_down_el = ConfHelper.findAndChange(this.tpl_move_down_el, this.el, null);
            $addHandler(move_down_el, 'click', Function.createDelegate(this, this.moveDownClicked));
        }
    },

    _createPhoto : function ()
    {
        var photo_el = ConfHelper.findAndChange(this.tpl_photo_el, this.el, null);

        if (this.photo)
        {
            ConfHelper.setVisible(photo_el, true);
        }
    },

    _createType : function ()
    {
        var checkbox_el = this.checkbox_el = ConfHelper.findAndChange(this.tpl_checkbox_el, this.el, null);
        var radio_el = this.radio_el =  ConfHelper.findAndChange(this.tpl_radio_el, this.el, null);
        var text_el = this.text_el = ConfHelper.findAndChange(this.tpl_text_el, this.el, null);
		var text_szt_el = this.text_szt_el = ConfHelper.findAndChange(this.tpl_text_szt_el, this.el, null);

        var type = this.parent.type;
        var count = this.count;
        switch (type)
        {
            case 'CONF_CHECK':
                ConfHelper.setVisible(text_el, false);
                ConfHelper.setVisible(radio_el, false);
                ConfHelper.setVisible(checkbox_el, true);
                ConfHelper.setVisible(text_szt_el, false);
				
                if (this.count)
                {
                    checkbox_el.checked = true;
                    if (this.read_only && !Configurator.prototype.admin)
                        checkbox_el.disabled = true;
                }
                $addHandler(checkbox_el, 'click', Function.createDelegate(this, this.checkboxClicked));
                break;

            case 'CONF_RADIO':
                ConfHelper.setVisible(text_szt_el, false);
                ConfHelper.setVisible(text_el, false);
                ConfHelper.setVisible(radio_el, true);
                ConfHelper.setVisible(checkbox_el, false);
                if (this.count)
                    radio_el.checked = true;
                $addHandler(radio_el, 'click', Function.createDelegate(this, this.radioClicked));
                break;

            case 'CONF_TEXT':
                ConfHelper.setVisible(text_szt_el, true);
                ConfHelper.setVisible(radio_el, false);
                ConfHelper.setVisible(text_el, true);
                ConfHelper.setVisible(checkbox_el, false);
                if (this.count)
                {
                    text_el.value = this.count;
                    if (this.read_only && !Configurator.prototype.admin)
                        text_el.disabled = true;
                }
                $addHandler(text_el, 'blur', Function.createDelegate(this, this.textBlurred));
                break;

            default:
        }
    },

    _createPrice : function ()
    {
        var price_el = ConfHelper.findAndChange(this.tpl_price_el, this.el, null);
        if (this.price === null || this.price === undefined)
            this.price = '';
        ConfHelper.attachText(price_el, this.price + ' PLN');
//		 price_el.style.background='red';
		if(this.el.rowIndex == 0)
		{
			price_el.className = 'konfig-cena-first';
		}else
		{
			price_el.className = 'konfig-cena';
		}

    },

    checkboxClicked : function ()
    {
        this.count = this.checkbox_el.checked ? 1 : 0;

        var conf = this.getConfigurator();
        conf.updateAsistant();
    },

    radioClicked : function ()
    {
        var prods = this.parent.products;

        for (var i = 0; i < prods.length; i++)
            if (prods[i] !== this)
                prods[i].radioCheck(false);

        this.radioCheck(true, true);
    },

    textBlurred : function ()
    {
        var text = this.text_el.value;
        if (text === null || text === undefined || text === '')
        {
            this.count = 0;
        }
        else
        {

            // check if numbers are only passed
            var match = /^\s*\d*\s*$/.test(text);
            if (!match)
            {
                alert("only numbers allowed");
                this.text_el.value = '';
                this.count = 0;
            }
            else
            {
                var count = parseInt(text);
                if (count <= 0)
                {
                    alert("have to be grater then 0");
                    this.count = 0;
                    this.text_el.value = '';
                }
                else
                    this.count = count;
            }
        }

        var conf = this.getConfigurator();
        conf.updateAsistant();
    },

    radioCheck : function (val, raiseEvent)
    {
        if (val)
        {
            this.radio_el.checked = true;
            this.count = 1;
        }
        else
        {
            this.radio_el.checked = false;
            this.count = 0;
        }

        if (raiseEvent)
        {
            var conf = this.getConfigurator();
            conf.updateAsistant();
        }
    },

    isChoosen: function ()
    {
        // this function will return if the product is selected
        // to be included in the basket

        return (this.count != 0);
    },

    getName : function (unit)
    {
        // this function will return name of the product. 
        // if more than one item is choosen(e.g. when the product
        // is of type 'text' than the number of items as a 
        // suffix will be added
        var name = this.long_name;
        if (!name)
            name = this.name;

        if (this.pack_count)
            name = this.pack_count + ' x ' + name;

        if (!unit && this.count !== null && this.count !== undefined && this.count > 1)
            name = this.count + ' x ' + name;

        return name;
    },

    // if unit set then unit price(without checking count) will be returned
    getPrice : function (unit)
    {
        // this function will return total price of the product. 
        var count = 0;
        var price = 0;
        try
        {
            count = parseInt(this.count);
        }
        catch(er){count = 0;}

        try
        {
            price = parseFloat(this.price);
        }
        catch (er){price = 0;}

        if (count && !unit)
            price = price * count;

        return price;
    },

    getCount : function ()
    {
        var count = 0;
        try
        {
            count = parseInt(this.count);
        }
        catch(er){count = 0;}

        return count;
    },

    remove: function ()
    {
        // remove product from parent node
        this.el.parentNode.removeChild(this.el);

        // remove product from kategory/subkategory 
        this.parent.removeProd(this);
    },

    editClicked: function ()
    {
        this.parent.editProd(this);
    },

    delClicked: function ()
    {
        this.remove();
    },

    moveDownClicked: function ()
    {
        this.parent.moveDownProd(this);
    },

    moveUpClicked: function ()
    {
        this.parent.moveUpProd(this);
    },

    _save: function (sdata)
    {
        var index = sdata.length;
        var count = this.count;
        if (!count)
            count = 0;
         
        sdata[index++] = this.menu_id;
        sdata[index++] = count;
        sdata[index++] = this.show_on_summary ? 1 : 0;
        sdata[index++] = this.long_name ? this.long_name : '';
        sdata[index++] = this.pack_count ? this.pack_count : 0;
        sdata[index++] = this.read_only ? 1 : 0;
    }
}

/*
Base class for all list
*/
function List()
{
    this.tpl_el = null;         // div to be showed as popup 
    this.popup = null;          // popup behavior

    this.callback = null;       // calback function
    this.selected = null;       // selected item 
}

List.prototype =
{
    beforeShow: function ()
    {
        // called before list is showed 
        // to init necessary data
        // ... could be overwritten in descendent classes
    },

    show: function (list_items, callback)
    {
        // will show list of products to choose
        // params:
        // list_items - array of items to be showed up 
        // callback - function to call upon completition
        //            index of the choosen item will be 
        //            given as a parameter in call to callback or null if nothing
        //            choosen

        this.beforeShow();

        this.ok_handler = Function.createDelegate(this, this.okClicked);
        this.cancel_handler = Function.createDelegate(this, this.cancelClicked);

        this.callback = callback;
        this.selected = null;

        this.initList(list_items);
        var div = this.tpl_el;
        // init click handlers
        $addHandler(this.tpl_ok_el, 'click', this.ok_handler);
        $addHandler(this.tpl_cancel_el, 'click', this.cancel_handler);

        var tmp_div = document.createElement('div');
 
        var popupBehavior = this.popup = $create(AjaxControlToolkit.ModalPopupBehavior, 
                                        {'PopupControlID': div.id}, null, null, tmp_div);
        popupBehavior.show();
    },

    hide: function ()
    {
        // remove click handlers
        $removeHandler(this.tpl_ok_el, 'click', this.ok_handler);
        $removeHandler(this.tpl_cancel_el, 'click', this.cancel_handler);

        this.popup.hide();
    },

    initList: function (prods)
    {
        /*
            should be override in derived classes
        */
    },

    okClicked: function ()
    {
        this.hide();
        this.callback(this.selected);
    },

    cancelClicked: function ()
    {
        this.hide();
        this.callback(null);
    }
}

function ProdList()
{
}

ProdList.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, ProdList, 'PRODLIST_');
}

ProdList.prototype = new List();

ProdList.prototype.beforeShow = function ()
{
    var show_on_summary = true;
    var read_only = false;
    var long_name = '';
    var pack_count = '';

    if (this.edited_prod)
    {
        var product = this.edited_prod;
        show_on_summary = product.show_on_summary;
        read_only = product.read_only;
        long_name = product.long_name;
        pack_count = product.pack_count;
    }
    // turn on show_on_summary checkebox
    this.tpl_show_on_summary_check_el.checked = show_on_summary;
    this.tpl_read_only_check_el.checked = read_only;

    this.tpl_long_name_el.value = long_name;
    var method = ConfData.prototype.ajaxUrl + '&type=get_comp_names&id=' + this.kat_id;

    // this hack will disable encodeURIComponent function which is used by Sys.Net.WebServiceProxy.invoke
    // function and which spoils our url
    //encodeURIComponent = function(s){return s;}
	ConfData.prototype.homeUrl = "http://"+ConfData.prototype.homeUrl+"/";
//	alert(ConfData.prototype.homeUrl);
//	alert(method);

    var auto_complete = this.auto_complete = $create(AjaxControlToolkit.AutoCompleteBehavior, 
                                        {'servicePath' : ConfData.prototype.homeUrl,
                                        'serviceMethod' : method}, 
                                        null, null, this.tpl_long_name_el);

    this.tpl_pack_count_el.value = pack_count;
}

ProdList.prototype.okClicked = function ()
{
    this.hide();
    var checkbox = this.tpl_show_on_summary_check_el;
    var checked = checkbox.checked;
    var read_only = this.tpl_read_only_check_el.checked;
    var pack_count = this.tpl_pack_count_el.value;
    try
    {
        pack_count = parseInt(pack_count);
    }
    catch(ex)
    {
        pack_count = 0;
    }

    this.callback(this.selected, checked, this.tpl_long_name_el.value, pack_count, read_only);
}

ProdList.prototype.initList = function (prods)
{
    // will init list of products to choose
    // params:
    // prods - array of products 

    //remove current products 
    var prod_parent_el = this.tpl_prod_el_parent;
    while (prod_parent_el.lastChild)
        prod_parent_el.removeChild(prod_parent_el.lastChild);

    var func = function(o, s, menu_id)
    {
        return (function()
                {
                o.selected = s;
                });
    }

    var edited_click_el = null;

    for (var i = 0; i < prods.length; ++i)
    {

        var name = prods[i].name;
        var producent = prods[i].producent;
        var part_nr = prods[i].part_nr;
        var prod_el = ConfHelper.createNewEl(prod_parent_el, this.tpl_prod_el, null);
        ConfHelper.setVisible(prod_el, true);
        var name_el = ConfHelper.findAndChange(this.tpl_prod_name_el, prod_el, null);
        ConfHelper.attachText(name_el, name);
        var producent_el = ConfHelper.findAndChange(this.tpl_prod_producent_name_el, prod_el, null);
        ConfHelper.attachText(producent_el, producent);
        var part_el = ConfHelper.findAndChange(this.tpl_prod_part_nr_el, prod_el, null);
        ConfHelper.attachText(part_el, part_nr);

        var click_el = ConfHelper.findAndChange(this.tpl_prod_click_el, prod_el, null, name_el);

        $addHandler(click_el, 'click',  func(this, i));
        if (this.edited_prod && prods[i].menu_id == this.edited_prod.menu_id)
            edited_click_el = click_el;
    }

    if (edited_click_el && edited_click_el.click)
        edited_click_el.click();
}

function Subkategory()
{
    this.parent =  null;        // points to kategory 
    this.el = null;             // Subkategory DOM element
    this.name = null;           // Subkategory name
    this.prod_el_parent = null; // parent node for products 

    this.products = [];
}

Subkategory.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, Subkategory, 'SUBKAT_');
}

Subkategory.prototype =
{
    init : function (s, parent, admin_subkats, deep)
    {
        // copy all properties from k
        for (var name in s)
        {
            this[name] = s[name];
        }

        this.parent = parent;

        for (var i = 0; i < admin_subkats.length; ++i)
            if (admin_subkats[i].menu_id == this.menu_id)
            {
                this.adminSubkat = admin_subkats[i];
                if (!this.name)
                    this.name = this.adminSubkat.name;
                break;
            }
        this.products= [];

        if (deep)
        {
            var p = s.products;

            for (var i = 0; i < p.length; ++i)
            {
                this.products[i] = new Product();
                this.products[i].init(p[i], this, deep);
            }
        }
    },

    create : function (deep)
    {
        this._createSub();
        this._createProd();
        this._createDelSubkat();
        this._createAddProd();
        this._createChilds(deep);
    },

    _createSub : function ()
    {
        var el = this.el = ConfHelper.createNewEl(this.parent.subkat_el_parent, this.tpl_el, null);
        var name_el = ConfHelper.findAndChange(this.tpl_name_el, el, null, el);
        ConfHelper.attachText(name_el, this.name);

        ConfHelper.setVisible(el, true);
    },

    _createDelSubkat: function ()
    {
        // will attach event listener to 'delete subkat' element if present
        if (this.tpl_del_el)
        {
            var del_el = ConfHelper.findAndChange(this.tpl_del_el, this.el, null);
            $addHandler(del_el, 'click', Function.createDelegate(this, this.delClicked));
        }
    },

    _createProd  : function ()
    {
        // exchange 'subkat_prod_div_el' with 'kat_prod_div_el'
        var subkat_prod_div = ConfHelper.findAndChange(this.tpl_prod_div_el, this.el, null);
        var kat_prod_div = ConfHelper.createNewEl(this.el, Kategory.prototype.tpl_prod_div_el, null);
        subkat_prod_div.parentNode.replaceChild(kat_prod_div, subkat_prod_div);
        ConfHelper.setVisible(kat_prod_div, true);

        this.prod_el_parent = ConfHelper.findAndChange(Product.prototype.tpl_el_parent, this.el, null);
        // remove product from div 
        ConfHelper.removeEl(ConfHelper.findAndChange(Product.prototype.tpl_el, this.el, null));
    },

    _createChilds : function (deep)
    {
        if (deep)
        {
            var prods = this.products;

            for (var i = 0; i < prods.length; ++i)
                prods[i].create(deep);
        }
    },

    _createAddProd: function ()
    {
        // will attach event listener to 'add product' element if present
        if (Product.prototype.tpl_add_el)
        {
            var add_el = ConfHelper.findAndChange(Product.prototype.tpl_add_el, this.el, null);
            $addHandler(add_el, 'click', Function.createDelegate(this, this.addProdClicked));
        }
    },

    remove: function ()
    {
        // remove subkategory from parent node
        this.el.parentNode.removeChild(this.el);

        // remove subkategory from tab 
        this.parent.removeSubkat(this);
    },

    delClicked: function ()
    {
        this.remove();
    },

    moveUpProd: function (prod)
    {
        var prod_index = Array.indexOf(this.products, prod);
        if (prod_index < 0)
            throw ("Specified product is not part of kategory[" + this.name + "] products");

        // can not move up first product
        if (prod_index == 0)
            return;

        // can not move if only one product 
        if (this.products.length <= 1)
            return;

        var prev_prod = this.products[prod_index - 1];

        // replace DOM nodes 
        var prod_node = prod.el;
        var prev_prod_node = prev_prod.el;
        var parent_node = prod.el.parentNode;
        parent_node.insertBefore(prod_node, prev_prod_node);

        // replace elements in array
        Array.removeAt(this.products, prod_index);
        Array.insert(this.products, prod_index - 1, prod); 
    },

    moveDownProd: function (prod)
    {
        var prod_index = Array.indexOf(this.products, prod);
        if (prod_index < 0)
            throw ("Specified product is not part of kategory[" + this.name + "] products");

        // can not move down the last product
        if (prod_index == (this.products.length - 1))
            return;

        // can not move if only one product 
        if (this.products.length <= 1)
            return;

        var next_prod = this.products[prod_index + 1];

        // replace DOM nodes 
        var prod_node = prod.el;
        var next_prod_node = next_prod.el;
        var parent_node = prod.el.parentNode;
        parent_node.insertBefore(next_prod_node, prod_node);

        // replace elements in array
        Array.removeAt(this.products, prod_index + 1);
        Array.insert(this.products, prod_index, next_prod); 
    },

    editProd: function (prod)
    {
        this.edited_prod = prod;

        if (!this.adminSubkat.productsRetrieved)
        {
            // retrieve via Ajax products for this kategory
            ConfHelper.sendAjax('get_prods', this.menu_id, '', Function.createDelegate(this, this.prodlistShowEdit)); 
        }
        else
        {
            this.prodlistShowEdit(this.adminSubkat.products, true);
        }
    },

    prodlistShowEdit: function (prods, as_obj)
    {
        if (!as_obj)
            prods = eval(prods);
    
        this.adminSubkat.productsRetrieved = true;
        this.adminSubkat.products = prods;

        var prodlist = new ProdList();
        prodlist.kat_id = this.menu_id;
        prodlist.edited_prod = this.edited_prod;
        prodlist.show(this.adminSubkat.products, Function.createDelegate(this, this.prodlistChoosedEdit)); 
    },

    prodlistChoosedEdit: function (prodIndex, show_on_summary, long_name, pack_count, read_only)
    {
        if (prodIndex === null || prodIndex < 0)
            return; 

        var edited_prod = this.edited_prod;

        // check if product already not added
        prod_menu_id = this.adminSubkat.products[prodIndex].menu_id;
        for (var i = 0; i < this.products.length; ++i)
        {
            if (this.products[i].menu_id == prod_menu_id && this.products[i] != edited_prod)
            {
                alert(ConfiguratorDefs.prototype.product_already_added);
                break;
            }
        }

        var product = new Product();
        product.init(this.adminSubkat.products[prodIndex], this, false);
        product.show_on_summary = show_on_summary;
        product.read_only = read_only;
        product.long_name = long_name;
        product.pack_count = pack_count;
        product.create(true, this.edited_prod);
        var prod_index = Array.indexOf(this.products, this.edited_prod);
        this.products[prod_index] = product;
        this.edited_prod = null;
    },

    addProdClicked: function ()
    {
        if (!this.adminSubkat.productsRetrieved)
        {
            // retrieve via Ajax products for this kategory
            ConfHelper.sendAjax('get_prods', this.menu_id, '', Function.createDelegate(this, this.prodlistShow)); 
        }
        else
        {
            this.prodlistShow(this.adminSubkat.products, true);
        }
    },

    prodlistShow: function (prods, as_obj)
    {
        if (!as_obj)
            prods = eval(prods);
    
        this.adminSubkat.productsRetrieved = true;
        this.adminSubkat.products = prods;

        var prodlist = new ProdList();
        prodlist.kat_id = this.menu_id;
        prodlist.show(this.adminSubkat.products, Function.createDelegate(this, this.prodlistChoosed)); 
    },

    prodlistChoosed: function (prodIndex, show_on_summary, long_name, pack_count, read_only)
    {
        if (prodIndex === null || prodIndex < 0)
            return; 

        // check if product already not added
        prod_menu_id = this.adminSubkat.products[prodIndex].menu_id;
        for (var i = 0; i < this.products.length; ++i)
        {
            if (this.products[i].menu_id == prod_menu_id)
            {
                alert(ConfiguratorDefs.prototype.product_already_added);
                break;
            }
        }

        var product = new Product();
        product.init(this.adminSubkat.products[prodIndex], this, false);
        product.show_on_summary = show_on_summary;
        product.read_only = read_only;
        product.long_name = long_name;
        product.pack_count = pack_count;
        product.create();
        this.products[this.products.length] = product;
    },

    set_adminSubkat: function (adminSubkat)
    {
        this.adminSubkat = adminSubkat;
    },

    removeProd: function (prod)
    {
        var prod_index = Array.indexOf(this.products, prod);
        if (prod_index < 0)
            throw ("Specified product is not part of subkategory[" + this.name + "] products");

        // remove from array
        Array.removeAt(this.products, prod_index);
    },

    getSelectedProds : function ()
    {
        var selprods = [];
        var count = 0;
        var prods = this.products;
        for (var i = 0; i < prods.length; ++i)
        {
            if (prods[i].isChoosen())
                selprods[count++] = prods[i];
        } 

        return selprods;
    },

    _save: function (sdata)
    {
        var index = sdata.length;
        var prods = this.products;
         
        sdata[index++] = this.menu_id;
        sdata[index++] = this.type;
        sdata[index++] = prods.length;

        for (var i = 0; i < prods.length; ++i)
        {
            prods[i]._save(sdata);
        }
    }
}

function SubkatList()
{
}

SubkatList.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, SubkatList, 'SUBKATLIST_');
}

SubkatList.prototype = new List();

SubkatList.prototype.initList = function (subkats)
{
    // will init list of subkategories to choose
    // params:
    // subkats - array of subkategories 

    //remove current subkategories  
    var name_parent_el = this.tpl_name_el_parent;
    while (name_parent_el.lastChild)
        name_parent_el.removeChild(name_parent_el.lastChild);

    var func = function(o, s)
    {
        return (function()
                {
                o.selected = s;
                });
    }

    for (var i = 0; i < subkats.length; ++i)
    {
        var name = subkats[i].name;
        var name_el = ConfHelper.createNewEl(name_parent_el, this.tpl_name_el, null);
        ConfHelper.attachText(name_el, name);
        ConfHelper.setVisible(name_el, true);

        $addHandler(name_el, 'click',  func(this, i));
    }
}

function Kategory()
{
    this.parent =  null;        // points to tab
    this.el = null;             // Kategory DOM element
    this.name = null;           // Kategory name
    this.div_el = null;         // Kategory div DOM element
    this.prod_el_parent = null; // parent node for products 

    this.subkategories = [];
    this.products = [];
}

Kategory.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, Kategory, 'KAT_');

    // init Subkategory prototype
    Subkategory.initPrototype(tplParams);

    // init Product prototype
    Product.initPrototype(tplParams);
}

Kategory.prototype =
{
    init : function (k, parent, admin_kats, deep)
    {
        // copy all properties from k
        for (var name in k)
        {
            this[name] = k[name];
        }

        this.parent = parent;

        for (var i = 0; i < admin_kats.length; ++i)
            if (admin_kats[i].menu_id == this.menu_id)
            {
                this.adminKat = admin_kats[i];
                if (!this.name)
                    this.name = this.adminKat.name;
                break;
            }

        this.subkategories = [];

        if (deep)
        {
            var admin_subkat = [];
            if (this.adminKat && this.adminKat.subkategories)
                admin_subkat = this.adminKat.subkategories;

            var s = k.subkategories;

            for (var i = 0; s && i < s.length; ++i)
            {
                this.subkategories[i] = new Subkategory();
                this.subkategories[i].init(s[i], this, admin_subkat, deep);
            }

            this.products= [];
            var p = k.products;

            for (var i = 0; p && i < p.length; ++i)
            {
                this.products[i] = new Product();
                this.products[i].init(p[i], this, deep);
            }
        }
    },

    create: function (deep)
    {
        this._createKat();
        this._createKatDiv();
        this._createSubkat();
        this._createProd();
        this._createChoosenProd();
        this._createDelKat();
        this._createAddSubkat();
        this._createAddProd();
        this._createInfo();
        this._createChilds(deep);
    },

    _createKat : function ()
    {
        // add new kategory 
        var el = this.el = ConfHelper.createNewEl(this.parent.kat_el_parent, this.tpl_el, null);
        var name_el = ConfHelper.findAndChange(this.tpl_name_el, el, null, el);
        ConfHelper.attachText(name_el, this.name);

        ConfHelper.setVisible(el, true);
        var click_el = ConfHelper.findAndChange(this.tpl_click_el, el, null, el);
        $addHandler(click_el, 'click', Function.createDelegate(this, this.clicked));
    },

    _createKatDiv : function ()
    {
        ConfHelper.findAndChange(this.tpl_div_el_parent, this.el, null);
        var div_el = this.div_el = ConfHelper.findAndChange(this.tpl_div_el, this.el, null);
        // prevent click event propagation on kategory div
        $addHandler(div_el, 'click', function(e){e.stopPropagation();});
    },

    _createSubkat : function ()
    {
        this.subkat_el_parent = ConfHelper.findEl(Subkategory.prototype.tpl_el_parent, this.el);
        this.subkat_div_el = ConfHelper.findAndChange(this.tpl_subkat_div_el, this.el, null);
        
        // remove subkategory from div 
        ConfHelper.removeEl(ConfHelper.findAndChange(Subkategory.prototype.tpl_el, this.el, null));
    },

    _createProd : function ()
    {
        this.prod_el_parent = ConfHelper.findEl(Product.prototype.tpl_el_parent, this.el);
        this.prod_div_el = ConfHelper.findAndChange(this.tpl_prod_div_el, this.el, null);
        // remove product from div 
        ConfHelper.removeEl(ConfHelper.findAndChange(Product.prototype.tpl_el, this.el, null));
    },

    _createChoosenProd : function ()
    {
        this.choosen_prod_div_el = ConfHelper.findAndChange(this.tpl_choosen_prod_div_el, this.el, null);

        this.choosen_prod_el_parent = ConfHelper.findAndChange(this.tpl_choosen_prod_el_parent, this.el, null);

        // remove choosen product from div 
        ConfHelper.removeEl(ConfHelper.findAndChange(this.tpl_choosen_prod_el, this.el, null));

        ConfHelper.setVisible(this.choosen_prod_div_el, false);
    },

    _createDelKat: function ()
    {
        // will attach event listener to 'delete kat' element if present
        if (this.tpl_del_el)
        {
            var del_el = ConfHelper.findAndChange(this.tpl_del_el, this.el, null);
            $addHandler(del_el, 'click', Function.createDelegate(this, this.delClicked));
        }
    },

    _createAddSubkat: function ()
    {
        // will attach event listener to 'add subkategory' element if present
        if (Subkategory.prototype.tpl_add_el)
        {
            var add_el = ConfHelper.findAndChange(Subkategory.prototype.tpl_add_el, this.div_el, null);
            $addHandler(add_el, 'click', Function.createDelegate(this, this.addSubkatClicked));
        }
    },

    _createAddProd: function ()
    {
        // will attach event listener to 'add product' element if present
        if (Product.prototype.tpl_add_el)
        {
            var add_el = ConfHelper.findAndChange(Product.prototype.tpl_add_el, this.div_el, null);
            $addHandler(add_el, 'click', Function.createDelegate(this, this.addProdClicked));
        }
    },

    _createInfo : function ()
    {
        var info_el = this.info_el = ConfHelper.findEl(this.tpl_info_el, this.el);
        $addHandler(info_el, 'click', Function.createDelegate(this, this.infoClicked));

        var info_div_el = this.info_div_el = ConfHelper.findEl(this.tpl_info_div_el, this.el);
        $addHandler(info_div_el, 'click', function(e){e.stopPropagation();});
        ConfHelper.setVisible(info_div_el, false);
        this.info_visible = false;

        if (Configurator.prototype.admin)
        {
            var info_text_area = this.info_text_area = document.createElement('textarea');
            info_text_area.style.width = '99%';
            info_text_area.style.height = '99%';
            info_div_el.appendChild(info_text_area);
        }
        else
        {
            if (this.info_text)
                info_div_el.innerHTML = this.info_text;
            else
                ConfHelper.setVisible(info_el, false);
        }
    },

    _createChilds : function (deep)
    {
        if (deep)
        {
            var subkats = this.subkategories;

            for (var i = 0; i < subkats.length; ++i)
                subkats[i].create(deep);

            var prods = this.products;

            for (var i = 0; i < prods.length; ++i)
                prods[i].create(deep);
        }
    },

    show: function ()
    {
        ConfHelper.setVisible(this.div_el, true);
        ConfHelper.setVisible(this.choosen_prod_div_el, false);

        this.shown = true;
    },

    hide: function ()
    {
        this.fillChoosenProds();

        ConfHelper.setVisible(this.div_el, false);
        ConfHelper.setVisible(this.choosen_prod_div_el, true);

        this.shown = false;
    },

    fillChoosenProds: function ()
    {
        var div = this.choosen_prod_div_el;
        var subs = this.subkategories;
        var prods;

        ConfHelper.removeAll(this.choosen_prod_el_parent);

        for (var s = 0; s < subs.length; ++s)
        {
            prods = subs[s].products;

            for (var i = 0; i < prods.length; ++i)
            {
                if (prods[i].isChoosen())
                {
                    // add new kategory 
                    var choosenProdEl = ConfHelper.createNewEl(this.choosen_prod_el_parent, this.tpl_choosen_prod_el);
                    ConfHelper.setVisible(choosenProdEl, true);
                    var nameEl = ConfHelper.findAndChange(this.tpl_choosen_prod_name_el, div, null, choosenProdEl);
                    ConfHelper.attachText(nameEl, prods[i].getName());

                    var priceEl = ConfHelper.findAndChange(this.tpl_choosen_prod_price_el, div, null, choosenProdEl);
                    ConfHelper.attachText(priceEl, prods[i].getPrice().toFixed(2));
                }
            }
        }

        var prods = this.products;

        for (var i = 0; i < prods.length; ++i)
        {
            if (prods[i].isChoosen())
            {
                // add new kategory 
                var choosenProdEl = ConfHelper.createNewEl(this.choosen_prod_el_parent, this.tpl_choosen_prod_el);
                ConfHelper.setVisible(choosenProdEl, true);
                var nameEl = ConfHelper.findAndChange(this.tpl_choosen_prod_name_el, div, null, choosenProdEl);
                ConfHelper.attachText(nameEl, prods[i].getName());

                var priceEl = ConfHelper.findAndChange(this.tpl_choosen_prod_price_el, div, null, choosenProdEl);
                ConfHelper.attachText(priceEl, prods[i].getPrice().toFixed(2));
            }
        }
    },

    clicked: function ()
    {
        if (ConfHelper.getVisible(this.div_el))
            this.hide();
        else
            this.show();
    },

    remove: function ()
    {
        // remove kategory from parent node
        this.el.parentNode.removeChild(this.el);

        // remove kategory from tab 
        this.parent.removeKat(this);
    },

    removeSubkat: function (subkat)
    {
        var subkat_index = Array.indexOf(this.subkategories, subkat);
        if (subkat_index < 0)
            throw ("Specified subkategory is not part of kategory[" + this.name + "] subkategories");

        // remove from array
        Array.removeAt(this.subkategories, subkat_index);
    },

    removeProd: function (prod)
    {
        var prod_index = Array.indexOf(this.products, prod);
        if (prod_index < 0)
            throw ("Specified product is not part of kategory[" + this.name + "] products");

        // remove from array
        Array.removeAt(this.products, prod_index);
    },

    infoClicked: function (e)
    {
        e.stopPropagation();
        ConfHelper.setVisible(this.info_div_el, !this.info_visible); 
        this.info_visible = !this.info_visible;
    },

    delClicked: function ()
    {
        this.remove();
    },

    addSubkatClicked: function ()
    {
        var subkatlist = new SubkatList();
        subkatlist.show(this.adminKat.subkategories, Function.createDelegate(this, this.subkatlistChoosed)); 
    },

    subkatlistChoosed: function (subkatIndex)
    {
        if (subkatIndex === null || subkatIndex < 0)
            return; 

        var subkat = new Subkategory();
        subkat.init(this.adminKat.subkategories[subkatIndex], this, false);
        subkat.set_adminSubkat(this.adminKat.subkategories[subkatIndex]);
        subkat.create();
        this.subkategories[this.subkategories.length] = subkat;
    },

    moveUpProd: function (prod)
    {
        var prod_index = Array.indexOf(this.products, prod);
        if (prod_index < 0)
            throw ("Specified product is not part of kategory[" + this.name + "] products");

        // can not move up first product
        if (prod_index == 0)
            return;

        // can not move if only one product 
        if (this.products.length <= 1)
            return;

        var prev_prod = this.products[prod_index - 1];

        // replace DOM nodes 
        var prod_node = prod.el;
        var prev_prod_node = prev_prod.el;
        var parent_node = prod.el.parentNode;
        parent_node.insertBefore(prod_node, prev_prod_node);

        // replace elements in array
        Array.removeAt(this.products, prod_index);
        Array.insert(this.products, prod_index - 1, prod); 
    },

    moveDownProd: function (prod)
    {
        var prod_index = Array.indexOf(this.products, prod);
        if (prod_index < 0)
            throw ("Specified product is not part of kategory[" + this.name + "] products");

        // can not move down the last product
        if (prod_index == (this.products.length - 1))
            return;

        // can not move if only one product 
        if (this.products.length <= 1)
            return;

        var next_prod = this.products[prod_index + 1];

        // replace DOM nodes 
        var prod_node = prod.el;
        var next_prod_node = next_prod.el;
        var parent_node = prod.el.parentNode;
        parent_node.insertBefore(next_prod_node, prod_node);

        // replace elements in array
        Array.removeAt(this.products, prod_index + 1);
        Array.insert(this.products, prod_index, next_prod); 
    },

    editProd: function (prod)
    {
        this.edited_prod = prod;

        if (!this.adminKat.productsRetrieved)
        {
            // retrieve via Ajax products for this kategory
            ConfHelper.sendAjax('get_prods', this.menu_id, '', Function.createDelegate(this, this.prodlistShowEdit)); 
        }
        else
        {
            this.prodlistShowEdit(this.adminKat.products, true);
        }
    },

    prodlistShowEdit: function (prods, as_obj)
    {
        if (!as_obj)
            prods = eval(prods);
    
        this.adminKat.productsRetrieved = true;
        this.adminKat.products = prods;

        var prodlist = new ProdList();
        prodlist.kat_id = this.menu_id;
        prodlist.edited_prod = this.edited_prod;
        prodlist.show(this.adminKat.products, Function.createDelegate(this, this.prodlistChoosedEdit)); 
    },

    prodlistChoosedEdit: function (prodIndex, show_on_summary, long_name, pack_count, read_only)
    {
        if (prodIndex === null || prodIndex < 0)
            return; 

        var edited_prod = this.edited_prod;

        // check if product already not added
        prod_menu_id = this.adminKat.products[prodIndex].menu_id;
        for (var i = 0; i < this.products.length; ++i)
        {
            if (this.products[i].menu_id == prod_menu_id && this.products[i] != edited_prod)
            {
                alert(ConfiguratorDefs.prototype.product_already_added);
                break;
            }
        }

        var product = new Product();
        product.init(this.adminKat.products[prodIndex], this, false);
        product.show_on_summary = show_on_summary;
        product.read_only = read_only;
        product.long_name = long_name;
        product.pack_count = pack_count;
        product.create(true, this.edited_prod);
        var prod_index = Array.indexOf(this.products, this.edited_prod);
        this.products[prod_index] = product;
        this.edited_prod = null;
    },

    addProdClicked: function ()
    {
        if (!this.adminKat.productsRetrieved)
        {
            // retrieve via Ajax products for this kategory
            ConfHelper.sendAjax('get_prods', this.menu_id, '', Function.createDelegate(this, this.prodlistShow)); 
        }
        else
        {
            this.prodlistShow(this.adminKat.products, true);
        }
    },

    prodlistShow: function (prods, as_obj)
    {
        if (!as_obj)
            prods = eval(prods);

        this.adminKat.productsRetrieved = true;
        this.adminKat.products = prods;

        var prodlist = new ProdList();
        prodlist.kat_id = this.menu_id;
        prodlist.show(this.adminKat.products, Function.createDelegate(this, this.prodlistChoosed)); 
    },

    prodlistChoosed: function (prodIndex, show_on_summary, long_name, pack_count, read_only)
    {
        if (prodIndex === null || prodIndex < 0)
            return; 

        // check if product already not added
        prod_menu_id = this.adminKat.products[prodIndex].menu_id;
        for (var i = 0; i < this.products.length; ++i)
        {
            if (this.products[i].menu_id == prod_menu_id)
            {
                alert(ConfiguratorDefs.prototype.product_already_added);
                break;
            }
        }

        var product = new Product();
        product.init(this.adminKat.products[prodIndex], this, false);
        product.show_on_summary = show_on_summary;
        product.read_only = read_only;
        product.long_name = long_name;
        product.pack_count = pack_count;
        product.create();
        this.products[this.products.length] = product;
    },

    set_adminKat: function (adminKat)
    {
        this.adminKat = adminKat;
    },

    retrieveAdminProducts: function ()
    {
        var prods = this.adminKat.products = [];

        for (var i = 0; i < 4; ++i)
        {
            prods[i] = new Product();
            prods[i].name = 'Prod' + i;
            prods[i].price = i + 1;
        }
    },

    getSelectedProds : function ()
    {
        var selprods = [];
        var count = 0;
        var prods = this.products;
        for (var i = 0; i < prods.length; ++i)
        {
            if (prods[i].isChoosen())
                selprods[count++] = prods[i];
        } 

        var subkats = this.subkategories;
        for (var i = 0; i < subkats.length; ++i)
        {
            selprods = selprods.concat(subkats[i].getSelectedProds());
        }
        return selprods;
    },

    _save: function (sdata)
    {
        var index = sdata.length;
        var subkats = this.subkategories;
        var prods = this.products;
        var info_text = "";
        if (this.info_text_area)
            info_text = this.info_text_area.value;
         
        sdata[index++] = this.menu_id;
        sdata[index++] = this.type;
        sdata[index++] = info_text ? info_text : "";
        sdata[index++] = subkats.length;
        sdata[index++] = prods.length;

        for (var i = 0; i < subkats.length; ++i)
        {
            subkats[i]._save(sdata);
        }

        for (var i = 0; i < prods.length; ++i)
        {
            prods[i]._save(sdata);
        }
    }
}

function KatList()
{
}

KatList.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, KatList, 'KATLIST_');
}

KatList.prototype = new List();

KatList.prototype.initList = function (kats)
{
    // will init list of kategories to choose
    // params:
    // tabs - array of kategories 

    //remove current kategories  
    var name_parent_el = this.tpl_name_el_parent;
    while (name_parent_el.lastChild)
        name_parent_el.removeChild(name_parent_el.lastChild);

    var func = function(o, s)
    {
        return (function()
                {
                o.selected = s;
                });
    }

    for (var i = 0; i < kats.length; ++i)
    {
        var name = kats[i].name;
        var name_el = ConfHelper.createNewEl(name_parent_el, this.tpl_name_el, null);
        ConfHelper.attachText(name_el, name);
        ConfHelper.setVisible(name_el, true);

        $addHandler(name_el, 'click',  func(this, i));
    }
}

function Tab()
{
    this.parent = null;         // ConData which contains this tab
    this.el = null;             // Tab DOM element
    this.name = null;           // Tab name
    this.div_el = null;         // Tab div DOM element
    this.kat_el_parent = null;  // ID of the kategory parent node
    this.selected = false;       // indicates if tab selected
    this.summary = false;       // indicates that this is a summary tab... behaves differently

    this.kategories = [];
}

Tab.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, Tab, 'TAB_');

    // init Kategory prototype
    Kategory.initPrototype(tplParams);
}

Tab.prototype =
{
    init : function (t, parent, admin_tabs, deep)
    {
        // copy all properties from t
        for (var name in t)
        {
            this[name] = t[name];
        }

        this.parent = parent;
        
        for (var i = 0; i < admin_tabs.length; ++i)
            if (admin_tabs[i].menu_id == this.menu_id)
            {
                this.adminTab = admin_tabs[i];
                if (!this.name)
                    this.name = this.adminTab.name;
                break;
            }

        this.kategories = [];

        var admin_kats = [];
        if (this.adminTab && this.adminTab.kategories)
            admin_kats = this.adminTab.kategories;

        if (deep)
        {
            var k = t.kategories;

            for (var i = 0; k && i < k.length; ++i)
            {
                this.kategories[i] = new Kategory();
                this.kategories[i].init(k[i], this, admin_kats, deep);
            }
        }
    },

    create: function (deep)
    {
        if (this.summary)
        {
            var name_el = this.tpl_sum_name_el;
            this.name = name_el.innerHTML;
            this._createTab();
            this._createTabSumDiv();
            this._createTabSumBasket();
        }
        else
        {
            this._createTab();
            this._createTabDiv();
            this._createDelTab();
            this._createAddKat();
            this._createChilds(deep);
            if (Tab.prototype.tpl_sum_div_el == null)
			{
                this._createTabSumBasket();
			}
			else
			{
				///TODO
//				ConfHelper.setVisible(document.getElementById("tab-act"),false);
			}
        }

        // call global script if extests
        this.call_update_tab();
    },

    call_update_tab: function ()
    {
        // if global function to update tab exitsts
        // then call it so that it may change tabs appearance
        if (typeof(configurator_update_tab) === 'function')
        {
            var tab_index = this.parent.getTabIndex(this);
            var tab_count = this.parent.getTabCount(this);
            configurator_update_tab(this.el, tab_index, tab_count); 
        }
    },

    _createTab: function ()
    {
        var el = this.el = ConfHelper.createNewEl(null, this.tpl_el, null);
        var name_el = ConfHelper.findAndChange(this.tpl_name_el, el, null, el);
        ConfHelper.attachText(name_el, this.name);
        ConfHelper.setVisible(this.el, true);

        var click_el = this.click_el = ConfHelper.findAndChange(this.tpl_click_el, el, null, el);
        $addHandler(click_el, 'click', Function.createDelegate(this, this.clicked));
    },

    _createDelTab: function ()
    {
        // will attach event listener to 'delete tab' element if present
        if (this.tpl_del_el)
        {
            var del_el = ConfHelper.findAndChange(this.tpl_del_el, this.el, null);
            $addHandler(del_el, 'click', Function.createDelegate(this, this.delClicked));
        }
    },

    _createAddKat: function ()
    {
        // will attach event listener to 'add kategory' element if present
        if (Kategory.prototype.tpl_add_el)
        {
            var add_el = ConfHelper.findAndChange(Kategory.prototype.tpl_add_el, this.div_el, null);
            $addHandler(add_el, 'click', Function.createDelegate(this, this.addKatClicked));
        }
    },

    _createTabDiv: function ()
    {
        var div_el = this.div_el = ConfHelper.createNewEl(null, this.tpl_div_el, null); 
        
        this.kat_el_parent = ConfHelper.findAndChange(Kategory.prototype.tpl_el_parent, div_el, null);
        // remove kategory from tab div 
        ConfHelper.removeEl(ConfHelper.findAndChange(Kategory.prototype.tpl_el, div_el, null));

        // add prev/next buttons
        var next_el = ConfHelper.findAndChange(this.tpl_next_el, div_el, null);
        var prev_el = ConfHelper.findAndChange(this.tpl_prev_el, div_el, null);

        var tab_index = this.parent.getTabIndex(this);
        var tab_count = this.parent.getTabCount(this);

        if (tab_index == 0)
        {
            ConfHelper.setVisible(prev_el, false);
        }
        else
        {
            ConfHelper.setVisible(prev_el, true);
            $addHandler(prev_el, 'click', Function.createDelegate(this, this.prevClicked));
        }

        if ((tab_index + 1) >= tab_count)
        {
            ConfHelper.setVisible(next_el, false);
        }
        else
        {
            ConfHelper.setVisible(next_el, true);
            $addHandler(next_el, 'click', Function.createDelegate(this, this.nextClicked));
        }
    },

    _createChilds: function (deep)
    {
        // if deep create, than create also kategories
        if (deep)
        {
            var kats = this.kategories;

            for (var i = 0; i < kats.length; ++i)
                kats[i].create(deep);
        }
    },

    _createTabSumDiv: function ()
    {
        var div_el = this.div_el = ConfHelper.createNewEl(null, this.tpl_sum_div_el, null); 
        this.sum_prod_parent_el = ConfHelper.findAndChange(this.tpl_sum_prod_el_parent, div_el, null);
        this.total_price_el = ConfHelper.findAndChange(this.tpl_sum_prod_total_price_el, div_el, null);
    },

    _createTabSumBasket: function ()
    {
        var basket_count_el = this.basket_count_el = ConfHelper.findAndChange(this.tpl_sum_basket_count_el, this.div_el, null);
        if (!basket_count_el.value)
            basket_count_el.value = '1';

        var basket_add_el = ConfHelper.findAndChange(this.tpl_sum_basket_add_el, this.div_el, null);

        var form_el = ConfHelper.findAndChange(this.tpl_sum_basket_form_el, this.div_el, null);
        form_el.method = 'POST';
        form_el.action = ConfData.prototype.add_to_basket_Url;


        $addHandler(form_el, 'submit', Function.createDelegate(this, this.addToBasket));

        // add hidden input to form to store elements to be added to basket
        var hidden_el = this.hidden_el = document.createElement('input');
        hidden_el.type = 'hidden';
        hidden_el.name = 'text';
        form_el.appendChild(hidden_el);

    },

    addToBasket: function ()
    {
        var count = this.basket_count_el.value;
        var prods = this.parent.getSelectedProds();

        var sdata = [];
        var index = 0;
        sdata[index++] = count;
        sdata[index++] = prods.length;

        for (var i = 0; i < prods.length; i++)
        {
            sdata[index++] = prods[i].menu_id;
            sdata[index++] = prods[i].getName(true);
            sdata[index++] = prods[i].getPrice(true);
            sdata[index++] = prods[i].count;
        }

        var text = sdata.join('||');
        this.hidden_el.value = text;
    },

    initSum : function ()
    {
        var sum_prod_parent_el = this.sum_prod_parent_el;
        while (sum_prod_parent_el.lastChild)
            sum_prod_parent_el.removeChild(sum_prod_parent_el.lastChild);

        var total_price_el = this.total_price_el;
        while (total_price_el.lastChild)
            total_price_el.removeChild(total_price_el.lastChild);

        var loading_icon = ConfiguratorDefs.prototype.summary_avail_loading;
        var prods = this.parent.getSelectedProds();
        var avail_data = [];    // array used later to retrieve availability information using ajax
        var total_price = 0.0;
        for (var i = 0; i < prods.length; ++i)
        {
            if (!prods[i].show_on_summary)
                continue;

            var name = prods[i].getName();
            var price = prods[i].getPrice().toFixed(2);
            total_price += prods[i].getPrice();

            var prod_el = ConfHelper.createNewEl(sum_prod_parent_el, this.tpl_sum_prod_el, null);
            ConfHelper.setVisible(prod_el, true);

            var avail_el = ConfHelper.findAndChange(this.tpl_sum_prod_avail_el, prod_el, null);
            avail_el.src = loading_icon; 
            //avail_el.style.backgroundImage = 'url(' + loading_icon + ')';

            var name_el = ConfHelper.findAndChange(this.tpl_sum_prod_name_el, prod_el, null);
            ConfHelper.attachText(name_el, name);
            // for server name(first product) turn on bold font
            if (i == 0)
            {
                name_el.style.fontWeight = 'bold';
            }
            else
            {
                name_el.style.paddingLeft = '10px';
            }
            var price_el = ConfHelper.findAndChange(this.tpl_sum_prod_price_el, prod_el, null);
            ConfHelper.attachText(price_el, price);

            var avail = {};
            avail.avail_el = avail_el;
            avail.prod_db_id = prods[i].db_id;
            avail_data[avail_data.length] = avail;
        }
        // show total price
        ConfHelper.attachText(total_price_el, total_price.toFixed(2));

        // will be used to set availability icons after ajax call returned
        var a_obj = {};
        a_obj.avail_data = avail_data;
        a_obj.set_avail = function(ajax_string)
        {
            var ajax_data = eval(ajax_string);
            var a = this.avail_data;

            for (var i = 0; i < a.length; ++i)
            {
                var avail_el = a[i].avail_el;
                var code = ajax_data[i].Code;
                var name = ajax_data[i].Name;

                var avail_icon = ConfiguratorDefs.prototype.summary_avail_icon;
                var dotpos = avail_icon.lastIndexOf('.');
                var new_icon = avail_icon.substring(0, dotpos);
                new_icon += code + avail_icon.substring(dotpos , avail_icon.length);

                avail_el.src = new_icon;
                avail_el.title = name;
                //avail_el.style.backgroundImage = 'url(' + new_icon + ')';
            }
        }

        // create array of products ids
        var ids = [];

        for (var i = 0; i < avail_data.length; ++i)
            ids[i] = avail_data[i].prod_db_id;
                
        var text = ids.join('||');

        // retrieve via Ajax products for this kategory
        ConfHelper.sendAjax('get_avail', '', text, Function.createDelegate(a_obj, a_obj.set_avail)); 

    },

    show: function ()
    {
        if (this.summary)
        {
            this.initSum();
        }
        ConfHelper.setVisible(this.div_el, true);
        this.selected = true;
    },

    hide: function ()
    {
        ConfHelper.setVisible(this.div_el, false);
        this.selected = false;
    },

    remove: function ()
    {
        // remove tab from parent node
        this.el.parentNode.removeChild(this.el);

        // remove tab div from parent node
        this.div_el.parentNode.removeChild(this.div_el);
        
        // remove tab from ConfData
        this.parent.removeTab(this);
    },

    nextClicked : function ()
    {
        this.parent.nextTab(this);
    },

    prevClicked : function ()
    {
        this.parent.prevTab(this);
    },

    clicked: function ()
    {
        var tabs = this.parent.tabs;
        for (var i = 0; i < tabs.length; i++)
            tabs[i].hide(); 

        this.show();
    },

    delClicked: function ()
    {
        this.remove();
        
    },

    addKatClicked: function ()
    {
        var katlist = new KatList();
        katlist.show(this.adminTab.kategories, Function.createDelegate(this, this.katlistChoosed)); 
    },

    katlistChoosed: function (katIndex)
    {
        if (katIndex === null || katIndex < 0)
            return; 

        var kat = new Kategory();
        kat.init(this.adminTab.kategories[katIndex], this, false);
        kat.set_adminKat(this.adminTab.kategories[katIndex]);
        kat.create();
        this.kategories[this.kategories.length] = kat;
    },

    get_selected: function ()
    {
        return this.selected;
        
    },

    // will simulate clicking on the tab
    click : function ()
    {
        if (this.click_el.onclick)
            this.click_el.onclick();

        this.clicked();
    },

    removeKat: function (kat)
    {
        var kat_index = Array.indexOf(this.kategories, kat);
        if (kat_index < 0)
            throw ("Specified kategory is not part of tab[" + this.name + "] kategories");

        // remove from array
        Array.removeAt(this.kategories, kat_index);
    },

    scrollTo: function ()
    {
        var bounds = Sys.UI.DomElement.getBounds(this.el); 
        window.scrollTo(0, bounds.y);

    },

    set_adminTab: function (adminTab)
    {
        this.adminTab = adminTab;
    },

    getSelectedProds : function ()
    {
        var kats = this.kategories;
        var selprods = [];
        for (var i = 0; i < kats.length; ++i)
        {
            selprods = selprods.concat(kats[i].getSelectedProds());
        }
        return selprods;
    },

    _save: function (sdata)
    {
        var kats = this.kategories;
        var index = sdata.length;

        sdata[index++] = this.menu_id;

        sdata[index++] = kats.length;

        for (var i = 0; i < kats.length; ++i)
        {
            kats[i]._save(sdata);
        }
    }
}

function TabList()
{
}

TabList.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, TabList, 'TABLIST_');
}

// derive from List
TabList.prototype = new List();

TabList.prototype.initList = function (tabs)
{
    // will init list of tabs to choose
    // params:
    // tabs - array of tabs

    //remove current tabs
    var name_parent_el = this.tpl_name_el_parent;
    while (name_parent_el.lastChild)
        name_parent_el.removeChild(name_parent_el.lastChild);

    var func = function(o, s)
    {
        return (function()
                {
                o.selected = s;
                });
    }

    for (var i = 0; i < tabs.length; ++i)
    {
        var name = tabs[i].name;
        var name_el = ConfHelper.createNewEl(name_parent_el, this.tpl_name_el, null);
        ConfHelper.attachText(name_el, name);
        ConfHelper.setVisible(name_el, true);

        $addHandler(name_el, 'click',  func(this, i));
    }
}

function ConfData()
{
    this.mainDivID = null;
    this.tplParams = null;
    this.template = null;

    // tabs visible by client
    this.tabs = [];
    // contain tabs that could be created by admin
    this.adminTabs = [];
}

ConfData.prototype =
{
    init : function (c, configurator)
    {

        // copy all properties from c
        for (var name in c)
        {
            this[name] = c[name];
        }
        this.parent = configurator;

        // put ajaxUrl to the prototype
        // so that other classes may use it
        // without creating object
        ConfData.prototype.ajaxUrl = this.ajaxUrl;
        ConfData.prototype.homeUrl = this.homeUrl;
        ConfData.prototype.add_to_basket_Url = this.add_to_basket_Url;
        ConfData.prototype.add_to_offer_Url = this.add_to_offer_Url;

        // as this.tabs were passed as just objectes,
        // it has to be changed to be an array of
        // Tab objects
        var t = this.tabs;
        this.tabs = [];

        var admin_tabs = this.adminTabs; 

        for (var i = 0; i < t.length; ++i)
        {
            this.tabs[i] = new Tab();
            this.tabs[i].init(t[i], this, admin_tabs, true);
        }
        // init Tab prototype
        Tab.initPrototype(this.tplParams);

        // init TabList prototype
        TabList.initPrototype(this.tplParams);

        // init KatList prototype
        KatList.initPrototype(this.tplParams);

        // init SubkatList prototype
        SubkatList.initPrototype(this.tplParams);

        // init ProdList prototype
        ProdList.initPrototype(this.tplParams);

        // init Asistant prototype
        Asistant.initPrototype(this.tplParams);

        // init defs prototype
        ConfiguratorDefs.initPrototype(this.tplParams);

        // init prototype of ConfHelper itself 
        ConfHelper.initPrototype(this.tplParams, ConfHelper, 'CONFHELPER_');
    },

    nextTab: function (tab)
    {
        var tab_index = Array.indexOf(this.tabs, tab);
        if (tab_index < 0)
            throw ("Specified tab is not part of ConfData tabs");
        
        if ((tab_index + 1) >= this.tabs.length)
            throw ("Can not move to next tab");

        this.tabs[tab_index + 1].click();
    },

    prevTab: function (tab)
    {
        var tab_index = Array.indexOf(this.tabs, tab);
        if (tab_index < 0)
            throw ("Specified tab is not part of ConfData tabs");
        
        if (tab_index < 1)
            throw ("Can not move to prev tab");

        this.tabs[tab_index - 1].click();
    },

    removeTab: function (tab)
    {
        var tab_index = Array.indexOf(this.tabs, tab);
        if (tab_index < 0)
            throw ("Specified tab is not part of ConfData tabs");

        var selected = tab.get_selected();

        // remove from array
        Array.removeAt(this.tabs, tab_index);

        // select previous tab
        if (selected && this.tabs.length > 0)
            if (this.tabs.length > tab_index)
                this.tabs[tab_index].click();
            else
                this.tabs[tab_index - 1].click();

        this.call_update_tabs();
    },

    getTabIndex : function (tab)
    {
        var tab_index = Array.indexOf(this.tabs, tab);
        if (tab_index < 0)
            throw ("Specified tab is not part of ConfData tabs");

        return tab_index;
    },

    getTabCount : function ()
    {
        return this.tabs.length;
    },

    addSummary : function ()
    {
        var stab = new Tab();
        stab.init([], this, [], false);
        stab.summary = true;
        
        var tabs = this.tabs;
        tabs[tabs.length] = stab;
    },

    getSelectedProds : function ()
    {
        var tabs = this.tabs;
        var selprods = [];
        for (var i = 0; i < tabs.length; ++i)
        {
            selprods = selprods.concat(tabs[i].getSelectedProds());
        }
        var server = new Product();
        server.parent = this.tabs[this.tabs.length - 1];
        server.name = this.server_name;
        server.price = this.server_price;
        server.menu_id = this.conf_id;
        server.db_id = this.conf_id;
        var serarr = [server];
        
        selprods = serarr.concat(selprods);

        return selprods;
    },

    showSummary: function ()
    {
        var tabs = this.tabs;

        if (tabs[tabs.length - 1].summary)
        {
            tabs[tabs.length - 1].click();
            tabs[tabs.length - 1].scrollTo();
        }

            
    },

    call_update_tabs: function ()
    {
        var tabs = this.tabs;
            
        for (var i = 0; i < tabs.length; ++i)
        {
            tabs[i].call_update_tab();
        }
    },

    _save: function (sdata)
    {
        var index = sdata.length;
        var tabs = this.tabs;
            
        sdata[index++] = this.conf_id;
        sdata[index++] = tabs.length;
        
        for (var i = 0; i < tabs.length; ++i)
        {
            tabs[i]._save(sdata);
        }
    }
}

function Configurator()
{
    // will containg ConfData... assigned by json_encode 
    this.data = null;
    this.mainDiv = null;
}

Configurator.initPrototype = function (tplParams)
{
    ConfHelper.initPrototype(tplParams, Configurator, 'CONFIGURATOR_');
}

Configurator.prototype = 
{
    init : function ()
    {
        // this hack will disable encodeURIComponent function which is used by Sys.Net.WebServiceProxy.invoke
        // function and which spoils url in AutoCompleteBehavior(used by ProdList)
        // when additional parameter (true) is passed then the original function
        // will be invoked
        var ob = {};
        ob.org_encodeURIComponent = encodeURIComponent;
        encodeURIComponent = function(s, org){if (org) return ob.org_encodeURIComponent(s); return s;}

        Configurator.initPrototype(this.data.tplParams);

        var d = this.data;
        this.data = new ConfData();

        this.data.init(d, this);
        if (this.data.admin)
            this.adminInit();
        else
        {
            // add summary tab... if needed
            if (Tab.prototype.tpl_sum_div_el && Tab.prototype.tpl_sum_div_el != null)
			{
                this.data.addSummary();
			}else
			{
				//todo
				ConfHelper.setVisible(document.getElementById("tab-act"),false);
			}
        }
    },

    attachTemplate : function ()
    {
        var temp = this.data.template;
        var divID = this.data.mainDivID;
        var div = $get(divID);
        this.mainDiv = div;
        if (!div)
            throw ("Could not find main div[" + divID + "]");

        div.innerHTML = temp;
    },

    show : function (where)
    {
        // hide 'loading...' div
        ConfHelper.setVisible(this.tpl_loading_el, false);

        var ti = 0, ki = 0, pi = 0;;
        var tabs = this.data.tabs;
        var tab, kat, prod;

        for (ti = 0; ti < tabs.length; ++ti)
        {
            var tab = tabs[ti];
            tab.create(true);
        }
        if (tabs.length > 0)
            tabs[0].click();

        if (!this.data.admin)
        {
            //show configuration assistant within a while due to a bug in IE6
            setTimeout(Function.createDelegate(this, this.showAsistant), 1);
        }
    },

    showAsistant : function ()
    {
        // get configurator position to show asistant in the right place
        var bounds = Sys.UI.DomElement.getBounds(this.tpl_el); 

        this.asistant = new Asistant();
        this.asistant.init({}, this);
        this.asistant.create(bounds.x, bounds.y + bounds.height);

        this.updateAsistant();
    },

    showSummary: function ()
    {
        this.data.showSummary();
    },

    updateAsistant : function ()
    {
        if (!this.admin)
        {
            var prods = this.data.getSelectedProds();
            this.asistant.update(prods);
        }
    },

    adminInit: function ()
    {
        // add 'admin' to prototype so that other classes may check we
        // are in admin mode
        Configurator.prototype.admin = true;

        // add click handler for 'add tab'
        var add_tab_el = Tab.prototype.tpl_add_el;
        if (!add_tab_el)
            throw ("Element to add tab not specified");

        $addHandler(add_tab_el, 'click', Function.createDelegate(this, this.addTabClicked));

        // add click handler for 'save' button
        var save_el = this.tpl_save_el;
        if (!save_el)
            throw ("Element to save configuration not specified");

        $addHandler(save_el, 'click', Function.createDelegate(this, this.save));
        // initiate offer
        this._createOffer();
    },

    _createOffer: function ()
    {
        var offer_count_el = this.tpl_offer_count_el;

        if (!offer_count_el.value)
            offer_count_el.value = '1';

        var offer_add_el = this.tpl_offer_add_el;

        var offer_form_el = this.tpl_offer_form_el;
        offer_form_el.method = 'POST';
        offer_form_el.action = ConfData.prototype.add_to_offer_Url;


        $addHandler(offer_form_el, 'submit', Function.createDelegate(this, this.addToOffer));

        // add hidden input to form to store elements to be added to basket
        var hidden_el = this.hidden_el = document.createElement('input');
        hidden_el.type = 'hidden';
        hidden_el.name = 'text';
        offer_form_el.appendChild(hidden_el);
    },

    addToOffer: function ()
    {
        var count = this.tpl_offer_count_el.value;
        var prods = this.data.getSelectedProds();

        var sdata = [];
        var index = 0;
        sdata[index++] = count;
        sdata[index++] = prods.length;

        for (var i = 0; i < prods.length; i++)
        {
            sdata[index++] = prods[i].menu_id;
            sdata[index++] = prods[i].getName(true);
            sdata[index++] = prods[i].getPrice(true);
            sdata[index++] = prods[i].count;
        }

        var text = sdata.join('||');
        this.hidden_el.value = text;
    },

    save : function ()
    {

        var sdata = [];
        
        this.data._save(sdata);
        
        var t;
        for (var i = 0; i < sdata.length; ++i)
        {
            t = sdata[i] + '';
            
            sdata[i] = t.replace(/\|/g, '\\|');
        }


        var text = sdata.join('||');
        text = encodeURIComponent(text, true);

        var type = 'save';
        var id = this.data.conf_id;
        ConfHelper.sendAjax(type, id, text, function(d){if (d.match(/^ok/)) alert(ConfiguratorDefs.prototype.configurator_saved_text);}, true);
    },

    addTabClicked : function ()
    {
        var tablist = new TabList();
        tablist.show(this.data.adminTabs, Function.createDelegate(this, this.tablistChoosed)); 
    },

    tablistChoosed: function (tabindex)
    {
        if (tabindex === null || tabindex < 0)
            return;

        var tab = new Tab();
        tab.init(this.data.adminTabs[tabindex], this.data, false);
        tab.set_adminTab(this.data.adminTabs[tabindex]);
        this.data.tabs[this.data.tabs.length] = tab;
        tab.create();
        tab.click();
        this.data.call_update_tabs();
    }
}

