/*
 * This file is the javascript end of the editableform library.
 * The javascript end maintains the adding and deletion of items
 * from the form.  Also handles reordering, editing, and maintaining
 * data.
 *
 * (c) Joe Chrzanowski 2008
 */

var Types = {
    HEADER : 0,
    CHECKBOX : 1,
    RADIO : 2,
    SELECT : 3,
    TEXTAREA : 4,
    TEXTFIELD : 5
};

var Option = Class.create({
    holder : null,
    refs : { field : null, button : null },
    
    initialize : function (parentid,index) {
        this.holder = document.createElement("div");
        this.holder.setAttribute("id",index);
        
        var field = document.createElement("input");
        field.setAttribute('type','text');
        field.setAttribute('name','option_' + parentid + "_" + index);
        this.refs.field = field;
        this.holder.appendChild(field);
        
        var removeButton = document.createElement("input");
        removeButton.setAttribute("type","button");
        removeButton.setAttribute("value","Remove");
        removeButton.setAttribute("class","remove");
        removeButton.setAttribute("onClick","theform.RemoveOptionFrom(" + parentid + "," + index + ")");
        this.refs.button = removeButton;
        this.holder.appendChild(removeButton);
    },
    SetDefaultValue : function (value) {
        if (value) {
            this.refs.field.value = value;
        }
    },
    GetValue : function() {
        return this.refs.field.value;
    },
    Render : function () {
        return this.holder;
    }
});

CreateComplexElement = function(tag,attribs) {
    var element = document.createElement(tag);
    for (var property in attribs) {
        element.setAttribute(property,attribs[property]);
    }
    return element;
}

var OptionPanel = Class.create({
    id : null,
    options : {},
    count : 0,
    container : null,
    div : null,
    
    initialize : function (id) {
        this.id = id;
        this.container = document.createElement("div");
        this.div = document.createElement("div");
        this.div.setAttribute('class','option_holder');
        
        var attribs = {
            'type'        : 'button',
            'onClick'     : 'theform.AddOption(' + this.id + ')',
            'value'       : 'Add Option',
            'class'       : 'add'
        };
        var addbutton = CreateComplexElement("input",attribs);
        this.container.appendChild(addbutton);
    },
    AddOption : function(value) {
        var newoption = new Option(this.id,this.count);
        newoption.SetDefaultValue(value);
        this.div.appendChild(newoption.Render());
        newoption.refs.field.focus();
        this.count++;
    },
    GetOptions : function () {
        var retarr = new Array();
        for (var option in options) {
            retarr.push(option.GetValue());
        }
    },
    CountOptions : function() { return this.count; },
    RemoveOption : function(index) {
        for (x = 0; x < this.div.childNodes.length; x++) {
            if (this.div.childNodes[x].getAttribute("id") == index) {
                this.div.removeChild(this.div.childNodes[x]);
                return true;
            }
        }
        return false;
    },
    Render : function() {
        this.container.appendChild(this.div);
        this.container.appendChild(CreateComplexElement("input",{type:'button',onClick:'theform.StopEditing(' + this.id + ')',value:"Done Editing",'class':'done'}));
        return this.container;
    }
});

var LineItem = Class.create({
    name : '',
    base : null,
    options : null,
    location : 0,
    type : 0,
    title : '',
    references : {},
    
    initialize : function (title, type, base, references, important) {
        this.options = new OptionPanel(base.getAttribute("lineitemid"));
        this.title = title;
        this.base = base;
        this.type = type;
        this.references = references;
        
        if (important)
            this.references.important.checked = important;
    },
    
    // time to display:
    // 
    // .25 * options
    ShowOptionEditor : function () {
        Effect.BlindDown("options_" + this.base.getAttribute("lineitemid"),{duration:0.3 + (0.2 * Math.log(this.options.CountOptions()))});
        this.base.style.backgroundColor = "FFFFBB";
    },
    HideOptionEditor : function () {
        Effect.BlindUp("options_" + this.base.getAttribute("lineitemid"),{duration:0.3 + (0.2 * Math.log(this.options.CountOptions()))});
        this.base.style.backgroundColor = "white";
    },
    
    Bind : function (dbid) {
        this.references.dbid = CreateComplexElement("input",{type:"hidden",name:"dbid_" + this.base.getAttribute("lineitemid"),value:dbid});
        this.base.appendChild(this.references.dbid);
    },
    
    AddOption : function (value) { this.options.AddOption(value); },
    RemoveOption : function (index) { this.options.RemoveOption(index); },
    GetOptions : function() { return this.options.GetOptions(); },
    
    SetLocation : function (location) { this.location = location; },
    GetLocation : function () { return this.location; },
    
    SetTitle : function(title) { this.title = title; },
    GetTitle : function() { return this.title; },
    
    Render : function() {
        this.references.title.value = this.title;
        this.references.type.selectedIndex = this.type;
        this.references.options.appendChild(this.options.Render());
        
        return base;
    }
});

var EditableForm = Class.create({
    lineitems : null,
    listid : '',
    itemcount : 0,
    currentlyediting : -1,
    deletefromdb : new Array(),
    deletefield : null,
    
    initialize : function(listid) {
        this.listid = listid;
        this.lineitems = {};
    },
    
    _merge_refs : function(initial,addto) {
        var result = {};
        for (property in initial) {
            result[property] = initial[property];
        }
        for (property in addto) {
            if (result[property] == null) {
                result[property] = addto[property]
            }   
        }
        return result;
    },
    
    // this function modifies the lineitem template so the ids are right.
    // it also identifies important fields in the element and creates a 
    // reference array to them for easy use later.
    _update_ids : function (element,newid) {
        var references = {};
        if (element != null) {
            for (var x = 0; x < element.childNodes.length; x++) {
                if (Object.isElement(element.childNodes[x])) {
                    var refs = this._update_ids(element.childNodes[x],newid);
                    references = this._merge_refs(references,refs);
                }
            }
            
            // create the id by taking the name and appending the id
            theclass = element.getAttribute('class');
            if (element.getAttribute('name')) {
                references[element.getAttribute("name")] = element;
                
                newidstr = element.getAttribute('name') + "_" + newid;
                element.setAttribute('id',newidstr);
                element.setAttribute('name',newidstr);
            }
            else if (theclass && theclass.match("edit_handle")) {
                element.setAttribute("onClick","theform.BeginEditing(" + newid + ")");
                references.edit = element;
            }
            else if (theclass && theclass.match("delete_handle")) {
                element.setAttribute("onClick","theform.DeleteLineItem(" + newid + ")");
                references.del = element;
            }
        }
        return references;
    },
    GetLineItem : function (id) {
        if (this.lineitems[id] != null) return this.lineitems[id];
    },
    GetNewLineItem : function(title,type,important) {
        base = document.getElementById("itemtemplate");
        base = base.cloneNode(true);
        
        base.style.display = '';
        base.setAttribute('id','item_' + this.itemcount);
        base.setAttribute('lineitemid',this.itemcount);
        
        var referencearray = this._update_ids(base,this.itemcount);
        this.itemcount++;
        
        lineitem = new LineItem(title,type,base,referencearray,important);
        return lineitem;
    },
    BeginEditing : function(id) {
        if (this.currentlyediting >= 0) this.lineitems[this.currentlyediting].HideOptionEditor();
        if (this.lineitems[id]) {
            this.lineitems[id].ShowOptionEditor();
            this.currentlyediting = id;
        }
    },
    StopEditing : function (id) {
        this.lineitems[id].HideOptionEditor();
        this.currentlyediting = -1;
    },
    Bind : function (lineitemid, dbid) {
        this.lineitems[lineitemid].Bind(dbid);
    },
    AddLineItem : function (title,type,options,important) {
        newitem = this.GetNewLineItem(title,type,important);
        this.lineitems[newitem.base.getAttribute("lineitemid")] = newitem;
        
        if (options) {
            for (x = 0; x < options.length; x++) {
                newitem.AddOption(options[x]);
            }
        }
        
        list = $(this.listid);
        list.appendChild(newitem.Render());
        newitem.references.title.focus();
        UpdateList();
        $("itemcount").value = this.itemcount;
        return newitem.base.getAttribute("lineitemid");
    },
    DeleteFromDB : function (id) {
        if (this.lineitems[id].references.dbid) {
            var dbid = this.lineitems[id].references.dbid.value;
            this.deletefromdb.push(dbid);
            $("delete").value = this.deletefromdb.join(',');
        }
        else console.error("error nosuch dbid in " + id);
    },
    DeleteLineItem : function (id) {
        if (this.lineitems[id] && confirm("Are you sure you want to delete this item?")) {
            this.DeleteFromDB(id);
            $(this.listid).removeChild($("item_" + id));
            this.lineitems[id] = null;
        }
    },
    AddOption : function (index) {
        this.lineitems[index].AddOption();
    },
    RemoveOptionFrom : function (id,index) {
        this.lineitems[id].RemoveOption(index);
    }
});