﻿$.ui.TableList = Class.create();

Object.extend($.ui.TableList, $.Events.Methods);
Object.extend($.ui.TableList.prototype, $.base.Queriable);
Object.extend($.ui.TableList.prototype, $.base.Pageable);
Object.extend($.ui.TableList.prototype, $.base.Filterable);
Object.extend($.ui.TableList.prototype, $.base.Clickable);
Object.extend($.ui.TableList.prototype, $.base.Nestable);

Object.extend($.ui.TableList.prototype, {
    initialize: function(controlKeys, controlParts, commandButtons, controlFormat, query, nestedControls) {
        // Control Format
        if (controlFormat) this.controlFormat = controlFormat;

        // Save Query Object
        this.query = query;
        this.query.dataConnector.dto.State = formStates.Readonly;

        // Register UI Component Exceptions
        this['$.ui.unknownexception'] = $A();

        this['$.ui.unknownexception'].push(this._handleUIUnknownException);

        // Prepare the HTML Part
        //.. first find it
        if (Object.isUndefined($(controlParts.container))) {
            this['$.ui.unknownexception'].each(function(aFunc) {
                aFunc.call(this);
            });
        }
        else {
            this.htmlPartName = controlParts.container;

            // Hide all parts before displaying them
            repeatingParts = $$Select(null, this.htmlPartName);
            repeatingParts.invoke('hide');
        }

        // Add functionality to Buttons as per commandButtons
        if (this.isClickable) {
            this.commandButtons = commandButtons;
            this._attachButtonBehaivior();
        }

        if (this.isNestable) {
            this.innerControls = nestedControls;
            this._bindInnerControls();
        }

        if (this.isQueriable) {
            // Listen to Important Query (AJAX) events...and be ready to react...
            query.bindAsDataConnectorEventListener('$.query.success', this._handleQuerySuccess.bind(this));
            query.bindAsDataConnectorEventListener('$.query.failure', this._handleQueryFailure.bind(this));
            query.bindAsDataConnectorEventListener('$.query.exception', this._handleQueryException.bind(this));
        }

        if (this.isPageable) {
            this.pageNo = 0;
        }
    },

    _handleQuerySuccess: function(memo, data) {
        // Get the htmlPart
        this.presentElements = $$Select(null, this.htmlPartName);
        var htmlPart = this.presentElements.length > 0 ? this.presentElements[0] : undefined;

        // Let's set spacing around the part
        if (this.controlFormat.padding) {
            htmlPart.setStyle({ paddingBottom: this.controlFormat.padding });
        }

        if (htmlPart) {
            htmlPart.appear();

            // Do we need more or less?
            // listType: 'as-is', 'xact-count', 'shrink-grow', 'pager'

            // As-Is Calculation function                                
            var _defaultListType = function() {
                return Math.min(data.length - this.presentElements.length, 0);
            };

            // Xact-Count Calculation function
            var _xactCount = function(listCount) {
                return Math.min(data.length, listCount) - this.presentElements.length;
            };

            // Pager calculation function
            var _pagerCount = function(pageSize) {
                return Math.min(data.length - this.pageNo * pageSize, pageSize) - this.presentElements.length;
            };

            var diff = _defaultListType.call(this);

            if (this.controlFormat) {
                if (this.controlFormat.listType) {
                    switch (this.controlFormat.listType) {
                        case 'shrink-grow': // Fills as many htmlParts as records in the returning resultSet
                            diff = data.length - this.presentElements.length;
                            break;
                        case 'xact-count': // It attempts to fill list up to listCount--if possible.
                            if (this.controlFormat.listCount) {
                                diff = _xactCount.call(this, this.controlFormat.listCount);
                            }
                            break;
                        case 'pager':
                            diff = _pagerCount.call(this, this.controlFormat.pageSize);
                            break;
                        default: // as-is is default
                            break;
                    }
                }
            }

            // Add/Remove parts...
            if (diff > 0) {
                // Add as many repeating elements as necessary
                for (var i = 0; i < diff; i++) {
                    var clonePart = htmlPart.deepClone();
                    // Add the new part at the end of the list
                    Element.insert(this.presentElements.last(), {
                        'after': clonePart
                    });
                }
            }
            else {
                if (diff < 0) {
                    // Remove the extra parts
                    var length = this.presentElements.length;
                    for (var i = 0; i < -diff; i++) {
                        Element.remove(this.presentElements[length - i - 1]);
                    }
                }
            }

            // Refresh the htmlPart array (presentElements)
            this.presentElements = $$Select(null, this.htmlPartName);
            var startIndex = 0;

            // insert page handler
            if (this.controlFormat.listType == 'pager') {
                this._createPageHandler.call(this, memo, data, this.controlFormat, this.controlFormat.pagerContainer);
                startIndex = this.pageNo * this.controlFormat.pageSize;
            }

            // fill in repeatingPart with the required data

            // HACK: Sometimes we need to use SelectSingle instead of SelectMany and data is not an array
            if (!Object.isArray(data)) {
                var aData = $A();

                if (Object.isHash(data)) {
                    aData.push(data.toObject());
                } else {
                    aData.push(data);
                }

                data = aData;
            }

            data.slice(startIndex, startIndex + this.presentElements.length).each(function(record, i) {
                // Get a repeating part...
                var repeatingPart = $(this.presentElements[i]);

                // show the repeat part
                //Element.show(repeatingPart)
                repeatingPart.appear(this.presentElements[i].id, { duration: 1.5 });

                // Listen to MouseOver and Click Event
                if (this.controlFormat.clickModel) {
                    // Popup Window Function
                    var showPopup = function(url, title) {
                        popupWin = window.open(url, title, 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=775,height=700,left = 124.5,top = 109')
                    } .bind(this);


                    var _handlerMouseOverEvent = function(event) {
                        if (Prototype.Browser.IE) {
                            event.srcElement.setStyle({
                                cursor: 'pointer'
                            });
                        } else {
                            event.currentTarget.setStyle({
                                cursor: 'hand'
                            });
                        }
                    } .bind(this);

                    var _handlerMouseOutEvent = function(event) {
                        if (Prototype.Browser.IE) {
                            event.srcElement.setStyle({
                                cursor: 'default'
                            });
                        } else {
                            event.currentTarget.setStyle({
                                borderStyle: 'none',
                                cursor: 'default'
                            });
                        }
                    } .bind(this);

                    var _handleClickEvent = function(event) {
                        if (!this.controlFormat.clickModel.WindowTitle)
                            var windowTitle = 'Untitled';
                        else
                            var windowTitle = record[this.controlFormat.clickModel.WindowTitle];

                        if (!this.controlFormat.clickModel.URL)
                            throw Error;    // TODO: What to do here?

                        showPopup(record[this.controlFormat.clickModel.URL], windowTitle);
                    } .bind(this);


                    // PAGER HACK
                    // Elements are reused to simulate pages ...so events maybe duplicated
                    // so before adding a new handler...stop listening to the prior handler
                    repeatingPart.stopObserving('mouseover');
                    repeatingPart.stopObserving('mouseout');
                    repeatingPart.stopObserving('click');

                    repeatingPart.observe('mouseover', _handlerMouseOverEvent);
                    repeatingPart.observe('mouseout', _handlerMouseOutEvent);
                    repeatingPart.observe('click', _handleClickEvent);

                };

                // Get all input elements...
                var inputElements = repeatingPart.descendants();

                // Update
                inputElements.each(function(el) {
                    // Find the field specification from the DTO
                    var foundField = this.query.dataConnector.dto.fieldSet.find(function(field) {
                        return (field.inputName.toUpperCase() == el.id.toUpperCase());
                    });

                    if (foundField) {

                        var fieldValue = record[foundField.dbName];

                        if (foundField.map) {
                            switch (foundField.map.toUpperCase()) {
                                case 'TEXTAREA':


                                    break;
                                case 'BUTTON':
                                    // Buttons maybe restricted to be seen only by a subset of the users...
                                    if (foundField.securityPolicy) {
                                        var isPermissionGranted = this.query.validateSecurity(foundField.securityPolicy, record);

                                        if (isPermissionGranted) {
                                            el.style.visibility = 'visible';

                                            if (foundField.URLTemplate) {

                                                var _handleButtonClickEvent = function(URL) {
                                                    return function() {
                                                        window.location = URL;
                                                    }
                                                }

                                                var tempVar = $H();

                                                // Hack: Pass command parameters as possible candidates for evaluation
                                                // IMPORTANT: this code must be before the RECORD binding
                                                if (!Object.isUndefined(this.query.dataConnector.command.parameters.QueryString)) {
                                                    tempVar = tempVar.merge(this.query.dataConnector.command.parameters.QueryString);
                                                }

                                                // Hack: Pass the entire record as possible candidate for template replacement
                                                // IMPORTANT: Notice that fields in RECORD take presedence over fields in QueryString...
                                                tempVar = tempVar.merge(record);

                                                var template = new Template(foundField.URLTemplate);

                                                if (el.tagName.toUpperCase() == 'INPUT') {
                                                    el.observe('click', _handleButtonClickEvent(template.evaluate(tempVar)));
                                                } else {
                                                    button = el.descendants('input[id=' + foundField.inputName + 'type=button]');

                                                    if (button) {
                                                        // an Array...get only the first one
                                                        if (Object.isArray(button)) {
                                                            button = button.first();
                                                        }

                                                        el.observe('click', _handleButtonClickEvent(template.evaluate(tempVar)));
                                                    }
                                                }
                                            }
                                        } else {
                                            if (foundField.securityPolicy.action) {
                                                //this.query.setState(foundField.securityPolicy.action, el);
                                                action = foundField.securityPolicy.action;

                                                switch (action.predicate) {
                                                    case 'visibility':
                                                        el.style.visibility = action.state;
                                                        break;
                                                    case 'printwarning':
                                                        messageSpans = el.parentNode.select('#messageSpan');
                                                        messageSpan = null;

                                                        if (messageSpans.length > 0)
                                                            messageSpan = messageSpans[0];

                                                        if (messageSpan == null)
                                                            messageSpan = $span({ id: 'messageSpan', style: 'font-weight:bold; text-align: center; word-wrap: break-word' });

                                                        messageSpan.innerHTML = action.message;

                                                        el.parentNode.update(messageSpan);

                                                        break;
                                                    default:
                                                        el.style.visibility = 'hidden';
                                                }
                                            } else {
                                                el.style.visibility = 'hidden';
                                            }
                                        }
                                    }
                                    break;
                                case 'LINKTEMPLATE':
                                    if (foundField.URLTemplate) {
                                        var template = new Template(foundField.URLTemplate);

                                        if (!Object.isHash(record))
                                            URLPath = template.evaluate($H(record));
                                        else
                                            URLPath = template.evaluate(record);

                                        if (foundField.clickModel) {
                                            switch (foundField.clickModel.mode) {
                                                case 'webpage':
                                                    el.setAttribute("href", URLPath);

                                                    break;
                                                default:
                                                    var showPopup = function(url, title, event) {
                                                        popupWin = window.open(url, title, 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=775,height=700,left = 124.5,top = 109')
                                                        event.stop();
                                                    };

                                                    el.setAttribute("href", '');
                                                    el.stopObserving('click');
                                                    el.observe('click', showPopup.bind(this, URLPath, record[foundField.clickModel.windowTitle]));
                                                    break;
                                            }
                                        } else {
                                            if (el.tagName.toUpperCase() == 'A') {
                                                el.setAttribute("href", URLPath);
                                                //el.setAttribute("target", "_blank");
                                            } else {
                                                hRef = el.descendants('a');

                                                if (hRef) {
                                                    // an Array...get only the first one
                                                    if (Object.isArray(hRef)) {
                                                        hRef = hRef.first();
                                                    }

                                                    hRef.setAttribute("href", URLPath);
                                                    //hRef.setAttribute("target", "_blank");

                                                }
                                            }
                                        }
                                    }
                                    break;
                                case 'LINK':
                                    if (foundField.BaseURL)
                                        var fieldValue = foundField.BaseURL + fieldValue;

                                    el.setAttribute("href", fieldValue);
                                    //el.setAttribute("target", "_blank");

                                    break;

                                case 'IMAGE':
                                    // Look for the field specification
                                    var keyRules = this.controlFormat.fieldPresentationRules.find(function(thisEl) {
                                        return thisEl.inputID.toUpperCase() == foundField.inputName.toUpperCase();
                                    });

                                    if (keyRules) {
                                        if (keyRules.path) {
                                            var template = new Template(keyRules.path);

                                            var URLPath = template.evaluate($H(record));

                                            // Update the elements SCR property
                                            el.writeAttribute('src', URLPath + fieldValue);
                                        } else {
                                            // Update the elements SCR property
                                            el.writeAttribute('src', fieldValue);
                                        }
                                    } else {
                                        // Update the elements SCR property
                                        el.writeAttribute('src', fieldValue);
                                    }

                                    if (keyRules && keyRules.defaultPicture) {
                                        el.onerror = function() {
                                            this.src = keyRules.defaultPicture;
                                        };

                                    }
                                    break;
                                case 'CHECKBOX':
                                    el.checked = fieldValue;
                                    el.disabled = true;
                                    break;
                                case 'ARRAY':
                                    el.update(fieldValue.stringify());
                                    break;

                                default:
                                    break;
                            }
                        } else {
                            switch (foundField.type.toUpperCase()) {
                                case 'STRING':
                                    if (!Object.isUndefined(this.controlFormat)) {
                                        if (!Object.isUndefined(this.controlFormat.fieldPresentationRules)) {
                                            var keyRules = this.controlFormat.fieldPresentationRules.find(function(thisEl) {
                                                return thisEl.inputID.toUpperCase() == foundField.inputName.toUpperCase();
                                            });

                                            if (fieldValue) {

                                                var fieldValue = unescapeHTML2(fieldValue);

                                                if (keyRules) {
                                                    if (keyRules.stripHTML) {
                                                        fieldValue = fieldValue.stripTags();
                                                    }

                                                    if (keyRules.stripHTMLTags) {
                                                        keyRules.HTMLTags.each(function(HTMLTag) {
                                                            fieldValue = stripHTMLTag(fieldValue, HTMLTag);
                                                        }, this);
                                                    }

                                                    if (keyRules.charSize) {
                                                        fieldValue = fieldValue.strip().truncate(keyRules.charSize, ' <Hit Edit For more>');
                                                    }

                                                    el.update(fieldValue);

                                                    // Readonly?
                                                    if (this.isQueriable) {
                                                        if (this.query.dataConnector.dto.State = formStates.readonly) {
                                                            if (this._setFormToReadonly)
                                                                this._setFormToReadonly();
                                                        }
                                                    }

                                                    if (this.isQueriable) {
                                                        if (this.query.dataConnector.dto.State = formStates.readonly) {
                                                            if (this._disableInput)
                                                                this._disableInput(el);
                                                        }
                                                    }
                                                }
                                                else {
                                                    el.update(fieldValue);

                                                    if (this.isQueriable) {
                                                        if (this.query.dataConnector.dto.State = formStates.readonly) {
                                                            if (this._disableInput)
                                                                this._disableInput(el);
                                                        }
                                                    }
                                                }
                                            } else {
                                                el.update('');

                                                this._disableInput(el);
                                            }
                                        }
                                    }
                                    else {
                                        el.update(fieldValue);

                                        if (this.isQueriable) {
                                            if (this.query.dataConnector.dto.State = formStates.readonly) {
                                                if (this._disableInput)
                                                    this._disableInput(el);
                                            }
                                        }
                                    }
                                    break;

                                case 'DATE':
                                    thisDate = new Date(fieldValue);
                                    el.update(thisDate.toLocaleDateString());

                                    if (this.isQueriable) {
                                        if (this.query.dataConnector.dto.State = formStates.readonly) {
                                            if (this._disableInput)
                                                this._disableInput(el);
                                        }
                                    }

                                    break;
                                default:
                                    el.update(fieldValue);

                                    if (this.isQueriable) {
                                        if (this.query.dataConnector.dto.State = formStates.readonly) {
                                            if (this._disableInput)
                                                this._disableInput(el);
                                        }
                                    }

                                    break;
                            }
                        }
                    }
                }, this);
            }, this);
        }
    },

    _disableInput: function(element) {
        switch ($(element).tagName) {
            case 'input':
            case 'textarea':
            case 'select-one':
                $(element).disabled = true;
                break;
            default:
                break;
        }
    },

    _handleUIUnknownException: function() {
        alert('quitoi UnknownException');
        throw ('big error');
    },

    _setPageNo: function(pageNo, memo, data) {
        this.pageNo = pageNo;
        this._handleQuerySuccess(memo, data);
    },

    _createPageNumberSpan: function(text, pageNo, memo, data) {
        var thisObj = this;
        var span = new Element('span', {});
        Element.update(span, text);

        Event.observe(span, 'click', function() {
            thisObj._setPageNo(pageNo, memo, data);
        });
        return span;
    },

    _createPageHandler: function(memo, data, controlFormat, pagerContainer) {
        // Do nothing if there are no records to display..
        if (Object.isArray(data)) {
            if (data.length == 0) return;
        }

        var recordsetPaging = controlFormat.recordsetPaging;
        var pageSize = controlFormat.pageSize;
        var recordCount = data.length;
        var pageCount = Math.ceil(recordCount / pageSize);
        var pagerContainer = $(pagerContainer);

        // clear pager container
        Element.childElements(pagerContainer).each(function(ele) {
            Event.stopObserving(ele);
            Element.remove(ele);
        });
        Element.update(pagerContainer, '');

        // create first/last, previous/next links
        Object.extend(pagerContainer, {
            recordsetPaging: recordsetPaging,
            pageCount: pageCount,
            firstPage: this._createPageNumberSpan.call(this, '&lt;&lt;', 0, memo, data),
            previousPage: this._createPageNumberSpan.call(this, '&lt;', this.pageNo - 1, memo, data),
            nextPage: this._createPageNumberSpan.call(this, '&gt;', this.pageNo + 1, memo, data),
            lastPage: this._createPageNumberSpan.call(this, '&gt;&gt;', pageCount - 1, memo, data),
            pages: []
        });

        // insert first & previous
        Element.insert(pagerContainer, pagerContainer.firstPage);
        Element.insert(pagerContainer, pagerContainer.previousPage);

        var _insertPageNumber = function(i) {
            if (i == this.pageNo) {
                Element.insert(pagerContainer, '<strong>' + (i + 1) + '</strong>');
            }
            else {
                var span = this._createPageNumberSpan.call(this, i + 1, i, memo, data);
                pagerContainer.pages[i] = span;
                Element.insert(pagerContainer, span);
            }
        };

        // insert page numbers
        if (pageCount <= recordsetPaging) {
            for (var i = 0; i < pageCount; i++) {
                _insertPageNumber.call(this, i);
            }
        }
        else {
            var lowerBound = Math.max(0, Math.ceil(this.pageNo - recordsetPaging / 2));
            var upperBound = Math.min(lowerBound + recordsetPaging, pageCount);

            if (lowerBound > 0) {
                Element.insert(pagerContainer, '...');
            }

            for (var i = lowerBound; i < upperBound; i++) {
                _insertPageNumber.call(this, i);
            }

            if (lowerBound + recordsetPaging < pageCount) {
                Element.insert(pagerContainer, '...');
            }
        }

        // insert next & last
        Element.insert(pagerContainer, pagerContainer.nextPage);
        Element.insert(pagerContainer, pagerContainer.lastPage);

        this.pagerContainer = pagerContainer;
        // show pager
        Element.show(pagerContainer);

        // show/hide previous/next & first/last links
        (this.pageNo == 0 ? Element.hide : Element.show)(this.pagerContainer.firstPage);
        (this.pageNo == 0 ? Element.hide : Element.show)(this.pagerContainer.previousPage);
        (this.pageNo == this.pagerContainer.pageCount - 1 ? Element.hide : Element.show)(this.pagerContainer.nextPage);
        (this.pageNo == this.pagerContainer.pageCount - 1 ? Element.hide : Element.show)(this.pagerContainer.lastPage);
    },

    _handleQueryFailure: function() {
        Modalbox.show('warning.html', {
            title: 'Oops...',
            width: 300
        });
    },

    _handleQueryException: function() {
        Modalbox.show('warning.html', {
            title: 'Oops...',
            width: 300
        });
    }
});