/**
 * Create objects when the dom is ready
 */
window.addEvent('domready', function() {
    new nl.code.form.FormController();
});

/**
 * Core Class
 * Adds extra methods that can be used globally that are not included in the mootools lib
 *
 * @abstract
 */
Core = {
    /**
     * Create a namepsace
     * A namspace can be used to create a class with the same name as an exisiting class but in a different namespace
     *
     * @param string, the namespace to create
     */
    createNamespace: function(namespace) {
        var namespace_arr = namespace.split('.');
        var root = window;

        for (var i = 0; i < namespace_arr.length; i++) {
            if (! $type(root[namespace_arr[i]])) {
                root[namespace_arr[i]] = new Object();
            }

            root = root[namespace_arr[i]] ;
        }
    }
};

// create a namespace
Core.createNamespace('nl.code.form');

/**
 * FormController Class
 * This class controls the forms int the cms, it replaces static form fields with javascript field classes
 */
nl.code.form.FormController = new Class({
    /**
     * Constructor
     */
    initialize: function() {
        // get all input tags
        var field_arr = $(document.body).getElements('input');

        // loop through the fields and check on the css classname to create a custom field class
        for (var i = 0; i < field_arr.length; i++) {
            if (field_arr[i].hasClass('isodate')) {
                new nl.code.form.ISODateField(field_arr[i]);
            } else if (field_arr[i].hasClass('isodatetime')) {
                new nl.code.form.ISODatetimeField(field_arr[i]);
            }
        }
    }
});

/**
 * Field Class
 * This is the super class for all custom fields
 *
 * @abstract
 */
nl.code.form.Field = new Class({
    /**
     * Constructor
     *
     * @param Element, a form field
     */
    initialize: function(element) {
        this.element = element;

        // reference to this instance, used for closures
        var thisObject = this;

        // create an overlay element, this is used when the element has focus that there can be no interaction with other elements
        this.overlay = new Element('div', {
            'class': 'overlay',
            'styles': {
                width: Window.getScrollWidth().toInt(),
                height: Window.getScrollHeight().toInt()
            },
            'events': {
                'click': function(e) {
                    thisObject.blur();
                }
            }
        });
        // insert the div at the bottom of the body
        this.overlay.inject($(document.body));

        // when the field has focus, call the focus method
        this.element.addEvent('focus', function(e) {
            thisObject.focus();
            this.blur();
        });
    },

    /**
     * The element has focus
     *
     * @return void
     */
    focus: function() {
        // show the overlay
        this.overlay.setStyle('display', 'block');
    },

    /**
     * The element loses focus
     *
     * @return void
     */
    blur: function() {
        // hide the overlay
        this.overlay.setStyle('display', 'none');
    }
});

/**
 * TimeField Class
 * This is the super class for all custom fields
 * Instead of typing a value (integer), the user can use a slider to adjust the value
 *
 * @abstract
 */
nl.code.form.TimeField = new Class({
    Extends: nl.code.form.Field,

    /**
     * Constructor
     *
     * @param Element, an input element
     * @param integer, the maximum integer that can be givan as a value for this field
     */
    initialize: function(element, max_value) {
        // call parent constructor
        this.parent(element);

        // reference to this instance, used for closures
        var thisObject = this;

        // create the container for the slider
        this.slider_container = new Element('div', {
            'class': 'time-slider'
        });
        // insert the div at the bottom of the body
        this.slider_container.inject($(document.body));

        // get the coordinates of the input element
        var coordinates = this.element.getCoordinates();

        // set the coordinates for the slider container
        this.slider_container.setStyles({
            top: coordinates.top - (this.slider_container.getStyle('height').toInt() / 2),
            left: coordinates.left + coordinates.width - (this.slider_container.getStyle('width').toInt() / 2)
        });

        // create a knob for the slider, the element the user can drag
        this.slider_knob = new Element('div', {
            'class': 'time-slider-knob'
        });
        // insert the div in the slider container
        this.slider_knob.inject(this.slider_container);

        // create a mootools slider object
        this.slider = new Slider(this.slider_container, this.slider_knob, {
            // range: 0-max_value
            steps: max_value,
            // set it vertical
            mode: 'vertical',
            // onchange update the field's value
            onChange: function(step){
                var step = this.step.toString();

                if (this.step < 10) {
                    step = '0'+ this.step.toString();
                }

                thisObject.element.value = step;
            }
        });
        // set the current value of the field as the current step for the slider
        this.slider.set(this.element.value);
    },

    /**
     * The element has focus
     *
     * @return void
     */
    focus: function() {
        // call the parent focus method
        this.parent();

        // show the slider
        this.slider_container.setStyle('visibility', 'visible');
    },

    /**
     * The element loses focus
     *
     * @return void
     */
    blur: function() {
        // call the parent focus method
        this.parent();

        // hide the slider
        this.slider_container.setStyle('visibility', 'hidden');
    }
});

/**
 * MinuteField Class
 * A form field that represents a value for minutes, this can be in the range of 0 to 59
 *
 * @extends nl.code.form.TimeField
 */
nl.code.form.MinuteField = new Class({
    Extends: nl.code.form.TimeField,

    /**
     * Constructor
     *
     * @param Element, an input element
     */
    initialize: function(element) {
        this.parent(element, 59);
    },

    /**
     * Get the current minutes
     *
     * @return integer
     */
    getMinutes: function() {
        return this.element.value;
    }
});

/**
 * HourField Class
 * A form field that represents a value for minutes, this can be in the range of 0 to 23
 *
 * @extends nl.code.form.TimeField
 */
nl.code.form.HourField = new Class({
    Extends: nl.code.form.TimeField,

    /**
     * Constructor
     *
     * @param Element, an input element
     */
    initialize: function(element) {
        this.parent(element, 23);
    },

    /**
     * Get the current hours
     *
     * @return integer
     */
    getHours: function() {
        return this.element.value;
    }
});

/**
 * DateField Class
 *
 * @extends nl.code.form.Field
 */
nl.code.form.DateField = new Class({
    Extends: nl.code.form.Field,

    /**
     * Constructor
     *
     * @param Element, an input element
     */
    initialize: function(element) {
        this.parent(element);

        var date = null;

        this.iso_datetime = this.element.get('value');

        //YYYY-MM-DD HH:MM:SS
        var isodatetime_regexp = /^\d{4}\-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}$/i;
        if (isodatetime_regexp.test(this.iso_datetime)) {
            date = this.iso_datetime.substr(0, 10);
        }
        // create a nl.code.util.Date object
        this.date = new nl.code.util.Date(date);

        // render the date
        this.element.set('value', this.date.toString());

        // create the calendar
        this.calender = new nl.code.util.Calendar(this, this.date);
    },

    /**
     * @param Date
     * @return void
     */
    setDate: function(date) {
        this.date = date;
        this.element.set('value', this.date.toString());

        this.blur();
    },

    /**
     * Get the current hours
     *
     * @return integer
     */
    getDate: function() {
        return this.date.toString({
                leading_zeros: true,
                full_day: false,
                full_month: false,
                seperator: '-',
                year_index: 0,
                month_index: 1,
                day_index: 2
            });
    },

    /**
     * The element has focus
     *
     * @return void
     */
    focus: function() {
        // call the parent focus method
        this.parent();

        this.calender.show();
    },

    /**
     * The element loses focus
     *
     * @return void
     */
    blur: function() {
        // call the parent focus method
        this.parent();

        this.calender.hide();
    }
});


/**
 * ISODateField Class
 */
nl.code.form.ISODateField = new Class({
    /**
     * Constructor
     *
     * @param Element, an input element
     */
    initialize: function(element) {
        this.element = element;

        // set the element's class name
        this.element.set('class', 'date');

        this.iso_datetime = this.element.get('value');

        // create a DateField
        this.date_field = new nl.code.form.DateField(this.element);

        // add a listener to the form's submit event
        this.addFormListener();
    },

    /**
     * Add a listener to the form's submit event
     *
     * @return void
     */
    addFormListener: function() {
        // reference to this instance, used for closures
        var thisObject = this;

        // get the form
        var form = this.element.getParent('form');
        form.addEvent('submit', function(e) {
            thisObject.element.set('value', thisObject.date_field.getDate() +' 00:00:00');
        });
    }
});

/**
 * DatetimeField Class
 *
 * @extends nl.code.form.Field
 */
nl.code.form.ISODatetimeField = new Class({
    Extends: nl.code.form.ISODateField,

    /**
     * Constructor
     *
     * @param Element, an input element
     */
    initialize: function(element) {
        this.parent(element);

        var hours = '00';
        var minutes = '00';

        //YYYY-MM-DD HH:MM:SS
        var isodatetime_regexp = /^\d{4}\-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}$/i;
        if (isodatetime_regexp.test(this.iso_datetime)) {
            hours = this.iso_datetime.substr(11,2);
            minutes = this.iso_datetime.substr(14,2);
        }

        // create an input for the hours
        this.hour_container = new Element('input', {
            'type': 'text',
            'class': 'hour',
            'value': hours
        });
        // insert in the parent container add the bottom
        this.hour_container.inject(element.getParent());

        // create an input for the minutes
        this.minute_container = new Element('input', {
            'type': 'text',
            'class': 'minute',
            'value': minutes
        });
        // insert in the parent container add the bottom
        this.minute_container.inject(element.getParent());

        this.hour_field = new nl.code.form.HourField(this.hour_container);
        this.minute_field = new nl.code.form.MinuteField(this.minute_container);
    },

    /**
     * Add a listener to the form's submit event
     *
     * @return void
     */
    addFormListener: function() {
        // reference to this instance, used for closures
        var thisObject = this;

        // get the form
        var form = this.element.getParent('form');
        form.addEvent('submit', function(e) {
            thisObject.element.set('value', thisObject.date_field.getDate() +' '+ thisObject.hour_field.getHours() +':'+ thisObject.minute_field.getMinutes() +':00');
        });
    }
});

Core.createNamespace('nl.code.util');

/**
 * Calendar Class
 *
 * @namespace nl.code.util
 */
nl.code.util.Calendar = new Class({
    /**
     * Constructor
     *
     * @param DateField
     * @param nl.code.util.Date
     */
    initialize: function(field, date) {
        this.field = field;
        this.date = date;

        // the calendar container
        this.container = field.element.getParent().getElement('div.calendar-container');

        // guard
        if (! this.container) {
            alert('no calendar container found!');
            return;
        }

        // insert it at the bottom of the body
        this.container.inject($(document.body));

        // in this span is the month displayed
        this.month_container = this.container.getElement('span.current-month');

        // in this span is the year displayed
        this.year_container = this.container.getElement('span.current-year');

        // reference to this instance, used for closures
        var thisObject = this;

        // the anchor that sets the calendar to the next month
        var next_month = this.container.getElement('a.next-month');
        next_month.addEvent('click', function(e) {
            thisObject.updateMonth(1);
        });
        // the anchor that sets the calendar to the previous month
        var previous_month = this.container.getElement('a.previous-month');
        previous_month.addEvent('click', function(e) {
            thisObject.updateMonth(-1);
        });

        // the anchor that sets the calendar to the next year
        var next_year = this.container.getElement('a.next-year');
        next_year.addEvent('click', function(e) {
            thisObject.updateMonth(12);
        });
        // the anchor that sets the calendar to the previous year
        var previous_year = this.container.getElement('a.previous-year');
        previous_year.addEvent('click', function(e) {
            thisObject.updateMonth(-12);
        });

        // current date
        this.current_date = new nl.code.util.Date(new Date());

        // selected date
        this.selected_date = this.date;

        // determine the view date, if there was a selected date then use that one, else use the current date
        if (this.selected_date.day != null) {
            this.view_date = this.date;
        }
        if (this.view_date == null) {
            this.view_date = new nl.code.util.Date(new Date());
        }
    },

    /**
     * Show the calendar
     *
     * @return void
     */
    show: function() {
        // render the calendar
        this.renderCalendar();

        // get the coordinates of the input element
        var coordinates = this.field.element.getCoordinates();

        // set the styles for the calendar container
        this.container.setStyles({
            display: 'block',
            top: coordinates.top - 10,
            left: coordinates.left + coordinates.width - 20
        });
    },

    /**
     * Hide the calendar
     *
     * @return void
     */
    hide: function() {
        this.container.setStyle('display', 'none');
    },

    /**
     * Render the calendar
     *
     * @return void
     */
    renderCalendar: function() {
        // the first day of the month to display
        var start_date = new Date(this.view_date.year, this.view_date.month, 1);
        // the first day of the next month
        var end_date = new Date(this.view_date.year, this.view_date.month+1, 1);
        // if you substract two date you get the difference in milliseconds
        var days = Math.round((end_date-start_date)/1000/60/60/24);

        // at which cell we are
        var cell_counter = 0;
        // how much days are displayed
        var day_counter = 1;

        // a calendar can consist max out of 6 rows (1 day in the first row, 4 full weeks, 2 days in the last row)
        for (var row = 0; row <= 5; row++) {
            // a calendar has 7 columns, one for each day
            for (var col = 0; col <= 6; col++) {
                // get the day cell
                var cell = this.container.getElement('td.day_'+ row +'_'+ col);
                // make sure it is empty, no old dates are stored
                cell.empty();

                // first day in the week is sunday, change this to monday
                var day_in_week = start_date.getDay();
                if (day_in_week == 0) {
                    day_in_week = 6;
                } else {
                    day_in_week -= 1;
                }

                // getDate() returns the day in the week of the date (0 for sunday, 6 for saturday)
                if (cell_counter >= day_in_week && cell_counter <= (days + (day_in_week - 1))) {
                    cell.removeClass('empty');
                    var anchor = this.renderDay(day_counter++);
                    anchor.inject(cell);
                } else {
                    cell.addClass('empty');
                }

                cell_counter++;
            }
        }

        // set the appropriate month
        this.month_container.set('html', nl.code.util.Date.month_arr[this.view_date.month]);

        // set the appropriate year
        this.year_container.set('html', this.view_date.year);
    },

    /**
     * Render a day anchor
     *
     * @param integer
     * @return Element, an anchor
     */
    renderDay: function(day) {
        var thisObject = this;
        var day_anchor = new Element('a', {
            'href': 'javascript:void(null);',
            'html': day,
            'events': {
                'click': function(e) {
                    thisObject.setSelectedDate(day);
                }
            }
        });

        return day_anchor;
    },

    /**
     * The method is invoked when the client clicks on a day
     *
     * @param integer, between 1-31
     * @return void
     */
    setSelectedDate: function(day) {
        // set the internal selected date
        this.selected_date = new nl.code.util.Date(new Date(this.view_date.year, this.view_date.month, day));

        this.field.setDate(this.selected_date);
    },

    /**
     * Update the current month
     *
     * @param integer, the number of months to increase or decrease the current date with
     * @return void
     */
    updateMonth: function(months) {
        this.view_date.month += months;

        while (this.view_date.month < 0) {
            this.view_date.year--;
            this.view_date.month += 12;
        }

        while (this.view_date.month > 11) {
            this.view_date.year++;
            this.view_date.month -= 12;
        }

        this.renderCalendar();
    }
});

Core.createNamespace('nl.code.util');

/**
 * Date Class
 *
 * @namespace nl.code.util
 */
nl.code.util.Date = new Class({
    /**
     * Constructor
     *
     * @param Date/string
     * @param object, {seperator: '-', year_index: 0, month_index: 1, day_index: 2}
     */
    initialize: function(date, format) {
        // set the default date format
        if (format == null) {
            format = {
                seperator: '-',
                year_index: 0,
                month_index: 1,
                day_index: 2
            };
        }
        this.format = format;

        this.day = null ;
        this.month = null ;
        this.year = null ;

        if ($type(date) == 'string') {
            date = this.stringToDate(date, format);

            if (date != null) {
                this.day = date.getDate();
                this.month = date.getMonth();
                this.year = date.getFullYear();
            }
        } else if ($type(date) == 'date') {
            this.day = date.getDate();
            this.month = date.getMonth();
            this.year = date.getFullYear();
        }
    },

    /**
     * Convert this object to a string
     *
     * @param object
     * @return string
     */
    toString: function(format) {
        if (format == null) {
            format = {
                leading_zeros: true,
                full_day: false,
                full_month: true,
                seperator: ' ',
                year_index: 2,
                month_index: 1,
                day_index: 0
            };
        }

        var date_arr = [];

        // year part
        date_arr[format.year_index] = this.year;

        // month part
        if (format.full_month) {
            date_arr[format.month_index] = nl.code.util.Date.month_arr[this.month];
        } else if (format.leading_zeros && this.month < 9) {
            date_arr[format.month_index] = '0'+ (this.month + 1);
        } else {
            date_arr[format.month_index] = this.month + 1;
        }

        // day part
        if (format.full_day) {
            var date = new Date(this.year, this.month, this.day);
            date_arr[format.day_index] = nl.code.util.Date.day_arr[date.getDay()] +' '+ this.day;
        } else if (format.leading_zeros && this.day < 10) {
            date_arr[format.day_index] = '0'+ this.day;
        } else {
            date_arr[format.day_index] = this.day;
        }

        // wrap it up
        var date_str = '';
        for (var i = 0; i < date_arr.length; i++) {
            if (date_str) {
                date_str += format.seperator;
            }

            date_str += date_arr[i];
        }

        return date_str;
    },

    /**
     * Convert a string to a Date
     *
     * @param string
     * @param object, the used format
     * @return Date, the internal javascript Date object
     */
    stringToDate: function(date_str, format) {
        var item_arr = date_str.split(format.seperator);

        if (item_arr.length != 3) {
            return null;
        }

        return new Date(item_arr[format.year_index], (item_arr[format.month_index]-1), item_arr[format.day_index]) ;
    }
});
/**
 * Static variables
 */
nl.code.util.Date.month_arr = ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'];
nl.code.util.Date.day_arr = ['zondag', 'maandag', 'dinsdag', 'woendag', 'donderdag', 'vrijdag', 'zaterdag'];



/* no OO-code */

function sortTable(tableName, fieldName, sortOrder)
{
    var formTable      = document.forms['table_form'];
    var inputTableName = formTable.elements['table_name'];
    var inputFieldName = formTable.elements['field_name'];
    var inputSortOrder = formTable.elements['sort_order'];

    inputTableName.value = tableName;
    inputFieldName.value = fieldName;
    inputSortOrder.value = sortOrder;

    formTable.submit();
}

function setMPNOffset(tableName, offset, action)
{
    var formTable      = document.forms['table_form'];
    var inputTableName = formTable.elements['table_name'];
    var inputMPNOffset = formTable.elements['mpn_offset'];

    inputTableName.value = tableName;
    inputMPNOffset.value = offset;

    if (action) {
        formTable.action = action
    }

    formTable.submit();
}

function searchTable(tableName)
{
    var formTable      = document.forms['table_form'];
    var inputTableName = formTable.elements['table_name'];
    var inputSearchStr = formTable.elements['search_str'];

    inputTableName.value = tableName;
    inputSearchStr.value = document.getElementById('search_' + tableName).value;

    formTable.submit();
}

function filterTable(tableName, fieldName)
{
    var formTable      = document.forms['table_form'];
    var inputTableName = formTable.elements['table_name'];
    var inputFieldName = formTable.elements['field_name'];
    var inputSelectFilter = formTable.elements['select_filter'];

    inputTableName.value = tableName;
    inputFieldName.value = fieldName;

    selectElement = document.getElementById('select_filter_' + tableName + '_' + fieldName);
    inputSelectFilter.value = selectElement.options[selectElement.selectedIndex].value;

    formTable.submit();
}


/*/
function sortTable(tableName, sortField, sortOrder)
{
    var formTable      = document.getElementById(tableName+'_table_form');
    var inputFieldName = document.getElementById(tableName+'_field_name');
    var inputSortOrder = document.getElementById(tableName+'_sort_order');

    inputFieldName.value = sortField;
    inputSortOrder.value = sortOrder;

    formTable.submit();
}
function setMPNOffset(tableName, offset, action)
{
    var formTable      = document.getElementById(tableName+'_table_form');
    var inputMPNOffset = document.getElementById(tableName+'_mpn_offset');

    alert(tableName+'_mpn_offset');

    inputMPNOffset.value = offset;

    if (action) {
        formTable.action = action
    }

    formTable.submit();
} /* */


