var XControl = Class.create({
    name:null,
    view:null,
    selector:null,
    events: null,

    initialize: function(element)
    {
        this.loadview(element);
        this.events = new Array();
    },

    loadview: function(element)
    {
        this.view = $(element);
        this.name = this.view.id;
        this.view.control = this;
    },

    observe: function(eventName, callback)
    {
        if (!this.events[eventName])
            this.events[eventName] = new Array();
        this.events[eventName].push(callback);
    },

    resetObserve: function()
    {
        this.events = new Array();
    },

    fire: function(eventName, memo)
    {
        if (this.events[eventName])
            this.events[eventName].each(function(callback){
                callback(memo);
            });
    }
})

var FormControlSelector = '.formcontrol';
var FormControl = Class.create(XControl, {
    selector:FormControlSelector,
    form: null,
    noreload:null,
    url:null,
    container:null,

    initialize: function($super, element)
    {
        $super(element);
        this.noreload = this.view.hasClassName('noreload');
        if (this.view.hasClassName('stub'))
            this.render();
        else
            this.observeEvent();
    },

    observeEvent: function()
    {
        var control = this;
        this.view.observe('keypress', function(event){
            if (event.keyCode == 13 && (event.target.tagName=='INPUT'))
                control.submitSaveForm();
        });
        this.find('.submit').invoke('observe', 'click', function(){control.submitSaveForm()});
    },

    find: function()
    {
        var control = this;
        var args = $A(arguments);
        args.each(function(a, index){
            if (a[0]=='.') args[index] = control.container + a;
            else args[index] += control.container;
        })
        return Selector.findChildElements(this.view, args);
    },

    findOne: function(selector)
    {
        return this.find(selector).first();
    },

    checkForChanges: function(){},

    checkForFilterChanges: function(){},

    formBeforeSubmit: function(){},

    discardAllChanges: function(){},

    loadview: function($super, element)
    {
        $super(element);
        this.form = this.view.up('form');
        this.url = this.view.getAttribute('url');
        this.container = this.view.hasClassName('xcontainer') ? '.' + this.view.id : '';
    },

    render: function()
    {
        var params = this.getLocationHash();
        this.find('input').each(function(e){
            params[e.name] = e.value;
        })
        this.requestAjax(params);
    },

    refresh: function()
    {
        if (this.checkForChanges())
        {
            if (!confirm('Do you want to discard all changes?')) return;
            else this.discardAllChanges();
        }
        this.checkForFilterChanges();
        this.submitForm();
    },

    submitSaveForm: function()
    {
        if (this.checkForChanges())
        {
            this.setFormAction('save');
            this.checkForFilterChanges();
            this.submitForm();
        }
        else if (this.checkForFilterChanges())
        {
            this.submitForm();
        }
    },

    submitForm: function()
    {
        this.formBeforeSubmit();
        if (this.view.hasClassName('noajax'))
            this.submitFormNormal();
        else
            this.submitFormAjax();
    },

    submitFormAjax: function()
    {
        var action = this.getFormAction();
        if (!action){
            var hashable = this.getHashable();
            this.setLocationHash(hashable);
        }
        var params = this.serialize();
        this.showAjaxloader();
        this.requestAjax(params);
    },

    getHashable: function()
    {
        var elements = this.find('input:not(.nohash)', 'select:not(.nohash)', 'textarea:not(.nohash)');
        return Form.serializeElements(elements);
    },

    serialize: function(options)
    {
        var elements = this.find('input', 'select', 'textarea');
        return Form.serializeElements(elements, options);
    },

    setValue: function(e, value)
    {
        if (Object.isUndefined(e.originValue)) e.originValue = e.value;
        if (value != e.originValue){
            e.addClassName('changed');
            e.value = value;
        }
    },

    requestAjax: function(params)
    {
        var control = this;
        var wrapper = this.view.up();
        var action = this.getFormAction();
        Client.ajax(this.url, {
            parameters: params,
            onComplete: function(response){
                if(control.noreload)
                {
                    control.hideAjaxloader();
                    $$('.msgflash').invoke('update', response);
                }
                else
                {
                    wrapper.update(response);
                    control.loadview(wrapper.down(control.selector));
                    control.ajaxComplete();
                    control.observeEvent();
                }
                control.fire('ajaxcomplete', {action: action});
            }
        });
    },


    ajaxComplete: function()
    {
    },

    hideAjaxloader: function()
    {
        this.find('.loading_bar_holder').each(function(e){
            e.update('');
        });
        this.find('.loading_circle_holder').each(function(e){
            e.update('');
        });
    },

    showAjaxloader: function()
    {
        this.find('.loading_bar_holder').each(function(e){
            e.update('<input type="button" class="loading_bar"></input>');
        });
        this.find('.loading_circle_holder').each(function(e){
            e.update('<div class="loading_circle"></div>');
        });
        this.find('.loading_longbar_holder').each(function(e){
            e.update('<div class="ajaxloading"></div>');
        });
    },

    submitFormNoajax: function()
    {
        this.form.action = this.url;
        this.submitFormNormal();
    },

    submitFormNormal: function()
    {
        var action = this.getFormAction();
        if (action) this.form.method = 'post';
        this.form.submit();
    },

    setFormAction: function(action)
    {
        this.findOne('.action').value = action;
        return this;
    },

    getFormAction: function()
    {
        var e = this.findOne('.action');
        return e ? e.value : null;
    },

    setLocationHash: function(params)
    {
        this.setHash(this.name, params);
    },

    getLocationHash: function()
    {
        var hash = this.getHash(this.name);
        if (!hash) hash = '';
        return hash.toQueryParams();
    },

    setHash: function(key, value)
    {
        var value = value.replace(/&/g, ';').replace(/=/g, ':');
        History.set(key, value);
    },

    getHash: function(key)
    {
        var value = History.get(key);
        return value ? value.replace(/;/g, '&').replace(/:/g, '=') : null;
    }
})