/*!
 * Tine 2.0 - HumanResources 
 * Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)http://www.gnu.org/licenses/agpl.html AGPL Version 3
 */
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * Employee grid panel
 * 
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.EmployeeGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 * 
 * <p>Employee Grid Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>    
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.EmployeeGridPanel
 */
Tine.HumanResources.EmployeeGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    
    /**
     * @todo: make this generally available
     * @todo: this should be also available in the context menu
     * 
     * returns additional toobar items
     * 
     * @return {Array} of Ext.Action
     */
    getActionToolbarItems: function() {
        this.actions_export = new Ext.Action({
            text: String.format(this.app.i18n.ngettext('Export {0}', 'Export {0}', 50), this.i18nRecordsName),
            singularText: String.format(this.app.i18n.ngettext('Export {0}', 'Export {0}', 1), this.i18nRecordName),
            pluralText:  String.format(this.app.i18n.ngettext('Export {0}', 'Export {0}', 1), this.i18nRecordsName),
            translationObject: this.app.i18n,
            iconCls: 'action_export',
            scope: this,
            disabled: true,
            allowMultiple: true,
            actionUpdater: function(action, grants, records) {
                action.setDisabled(records.length == 0);
            },
            menu: {
                items: [
                    new Tine.widgets.grid.ExportButton({
                        text: this.app.i18n._('Export as ODS'),
                        format: 'ods',
                        iconCls: 'tinebase-action-export-ods',
                        exportFunction: 'HumanResources.exportEmployees',
                        gridPanel: this
                    }),
                    new Tine.widgets.grid.ExportButton({
                        text: this.app.i18n._('Export as XLS'),
                        format: 'xls',
                        iconCls: 'tinebase-action-export-xls',
                        exportFunction: 'HumanResources.exportEmployees',
                        gridPanel: this
                    })
                ]
            }
        });
        
        this.actionUpdater.addActions([this.actions_export]);
        
        var button = Ext.apply(new Ext.Button(this.actions_export), {
            scale: 'medium',
            rowspan: 2,
            iconAlign: 'top'
        });
        
        return [button];
    },
    
    /**
     * add custom items to context menu
     * 
     * @return {Array}
     */
    getContextMenuItems: function() {
        var items = [
            '-',
            this.actions_export
            ];
        
        return items;
    },
    
    renderSalutation: function(value, row, record) {
            if (! this.salutationRenderer) {
                this.salutationRenderer = Tine.Tinebase.widgets.keyfield.Renderer.get('Addressbook', 'contactSalutation');
            }
            return this.salutationRenderer(value, row, record);
    }
});

Tine.widgets.grid.RendererManager.register('HumanResources', 'Employee', 'salutation', Tine.HumanResources.EmployeeGridPanel.prototype.renderSalutation);

/*
 * Tine 2.0
 * 
 * @package     HumanResources
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.namespace('Tine.HumanResources.Model');

Tine.HumanResources.Model.WorkingTimeArray = [
    { name: 'id',            type: 'string'},
    { name: 'title',         type: 'string' },
    { name: 'json',          type: 'string'},
    { name: 'working_hours', type: 'float'}
];

Tine.HumanResources.Model.WorkingTime = Tine.Tinebase.data.Record.create(Tine.HumanResources.Model.WorkingTimeArray, {
    appName: 'HumanResources',
    modelName: 'WorkingTime',
    idProperty: 'id',
    titleProperty: 'title',
    // ngettext('Working Time', 'Working Times', n);
    recordName: 'Working Time',
    recordsName: 'Working Times',
    containerName: null,
    containersName: null,
    getTitle: function() {
        return this.get('title') ? this.get('title') : false;
    }
});

/**
 * @namespace Tine.HumanResources.Model
 * 
 * get default data for a new WorkingTime
 *  
 * @return {Object} default data
 * @static
 */ 
Tine.HumanResources.Model.WorkingTime.getDefaultData = function() {
    var data = {};
    return data;
};

/**
 * @namespace Tine.HumanResources.Model
 * 
 * get WorkingTime filter
 *  
 * @return {Array} filter objects
 * @static
 */ 
Tine.HumanResources.Model.WorkingTime.getFilterModel = function() {
    var app = Tine.Tinebase.appMgr.get('HumanResources');
    
    return [
        {label: i18n._('Quick Search'), field: 'query', operators: ['contains']}
    ];
};

/**
 * @namespace Tine.HumanResources
 * @class Tine.HumanResources.workingtimeBackend
 * @extends Tine.Tinebase.data.RecordProxy
 * 
 * Employee Backend
 */ 
Tine.HumanResources.workingtimeBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'HumanResources',
    modelName: 'WorkingTime',
    recordClass: Tine.HumanResources.Model.WorkingTime
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.ExceptionHandler
 * 
 * <p>Exception Handler for HumanResources</p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 */

Tine.HumanResources.handleRequestException = function(exception, callback, callbackScope) {
    if (! exception.code && exception.responseText) {
        // we need to decode the exception first
        var response = Ext.util.JSON.decode(exception.responseText);
        exception = response.data;
    }
    
    var app = Tine.Tinebase.appMgr.get('HumanResources');
    
    var defaults = {
        buttons: Ext.Msg.OK,
        icon: Ext.MessageBox.ERROR,
        fn: callback,
        scope: callbackScope,
        title: app.i18n._(exception.title),
        msg: app.i18n._(exception.message)
    };
    
    Tine.log.warn('Request exception :');
    Tine.log.warn(exception);

    switch(exception.code) {
        case 911: // HumanResources_Exception_NoContract
        case 912: // HumanResources_Exception_ContractNotEditable
        case 913: // HumanResources_Exception_RemainingNotBookable
        case 914: // HumanResources_Exception_NoAccount
        case 915: // HumanResources_Exception_ContractOverlap
        case 916: // HumanResources_Exception_ContractDates
        case 917: // HumanResources_Exception_NeedsYear
            Ext.MessageBox.show(defaults);
            break;
        // return false will the generic exceptionhandler handle the caught exception
        default:
            return false;
    }
    
    return true;
}

Tine.Tinebase.ExceptionHandlerRegistry.register('HumanResources', Tine.HumanResources.handleRequestException);/*
 * Tine 2.0
 * 
 * @package     HumanResources
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.namespace('Tine.HumanResources');

/**
 * register special renderer for contract workingtime_json
 */
Tine.widgets.grid.RendererManager.register('HumanResources', 'Contract', 'workingtime_json', function(v) {
    if (! v) {
        return 0;
    }
    var object = Ext.decode(v);
    var sum = 0;
    for (var i=0; i < object.days.length; i++) {
        sum = sum + parseFloat(object.days[i]);
    }
    return sum;
});

Tine.widgets.grid.RendererManager.register('HumanResources', 'FreeTime', 'account_id', function(v) {
    if (! v) {
        return '';
    }
    
    return v.year;
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.ContractEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Contract Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.ContractEditDialog
 */
Tine.HumanResources.ContractEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    appName: 'HumanResources',
    evalGrants: false,
    
    windowHeight: 300,
    
    /**
     * just update the contract grid panel, no persisten
     * 
     * @type String
     */
    mode: 'local',
    
    /**
     * The record is editable if the valid interval is in the future or not older than 2 hours
     * This property is set accordingly
     * 
     * @type 
     */
    allowEdit: null,

    displayNotes: true,

    /**
     * overwrite update toolbars function (we don't have record grants yet)
     * @private
     */
    updateToolbars: function() {
    },

    /**
     * inits the component
     */
    initComponent: function() {
        Tine.HumanResources.ContractEditDialog.superclass.initComponent.call(this);
    },
    
    /**
     * executed after record got updated from proxy, if json Data is given, it's used
     * 
     * @private
     */
    onRecordLoad: function(jsonData) {
        // interrupt process flow until dialog is rendered
        if (! this.rendered) {
            this.onRecordLoad.defer(250, this);
            return;
        }
        
        Tine.HumanResources.ContractEditDialog.superclass.onRecordLoad.call(this);
        
        var jsonData = jsonData ? Ext.decode(jsonData) : ! Ext.isEmpty(this.record.get('workingtime_json')) ? Ext.decode(this.record.get('workingtime_json')) : null;
        if (jsonData) {
            this.applyJsonData(jsonData);
        }
        
        if (! this.record.id) {
            this.getForm().findField('feast_calendar_id').setValue(Tine.HumanResources.registry.get('defaultFeastCalendar'));
        } else {
            this.window.setTitle(String.format(i18n._('Edit {0}'), this.i18nRecordName));
            this.getForm().findField('workingtime_template').setValue(null);
        }
        
        // disable fields if there are already some vacations booked
        // but allow setting end_date
        
        if (this.record.get('creation_time')) {
            if (! this.record.get('is_editable')) {
                this.getForm().items.each(function(formField) {
                    if (formField.name != 'end_date') {
                        formField.disable();
                    }
                }, this);
            }
        }
    },
    
    /**
     * applies the json data to the form
     * 
     * @param {Object} jsonData
     */
    applyJsonData: function(jsonData) {
        var days = jsonData.days,
        form = this.getForm(),
        sum = 0.0;

        for (var index = 0; index < 7; index++) {
            form.findField('weekdays_' + index).setValue(days[index]);
            sum = sum + parseFloat(days[index]);
        }
        
        form.findField('working_hours').setValue(sum);
    },
    
    updateWorkingHours: function(formField, newValue, oldValue) {
        var sum = 0;
        for (var index = 0; index < 7; index++) {
            sum += parseFloat(this.getForm().findField(('weekdays_' + index)).getValue());
        }
        
        this.getForm().findField('working_hours').setValue(sum);
    },
    
    /**
     * returns appropriate json for the template or the contract
     * 
     * @return {String}
     */
    getJson: function() {
        var values = this.getForm().getFieldValues(),
            days = [];
        
        for (var index = 0; index < 7; index++) {
            days[index] = parseFloat(values['weekdays_' + index]);
        }
        
        return Ext.encode({days: days});
    },

    /**
     * closes open subpanels on cancel
     */
    onCancel: function() {
        Tine.HumanResources.ContractEditDialog.superclass.onCancel.call(this);
    },
    
    /**
     * executed when record gets updated from form
     * @private
     */
    onRecordUpdate: function() {
        Tine.HumanResources.ContractEditDialog.superclass.onRecordUpdate.call(this);
        
        this.record.set('workingtime_json', this.getJson());
        this.record.set('feast_calendar_id', this.getForm().findField('feast_calendar_id').selectedContainer);
    },
    
    /**
     * returns dialog
     * 
     * NOTE: when this method gets called, all initalisation is done.
     * 
     * @return {Object}
     * @private
     */
    getFormItems: function() {
        var weekdayFieldDefaults = {
            
            xtype: 'uxspinner',
            strategy: new Ext.ux.form.Spinner.NumberStrategy({
                incrementValue : .5,
                alternateIncrementValue: 1,
                minValue: 0,
                maxValue: 24,
                allowDecimals : true
            }),
            decimalPrecision: 2,
            decimalSeparator: Tine.Tinebase.registry.get('decimalSeparator'),
            anchor: '100%',
            labelSeparator: '',
            allowBlank: true,
            columnWidth: 1/7,
            listeners: {
                scope:  this,
                blur: this.updateWorkingHours.createDelegate(this),
                spin: this.updateWorkingHours.createDelegate(this)
            }
        };
        
        return {
            xtype: 'tabpanel',
            border: false,
            plain:true,
            plugins: [{
                ptype : 'ux.tabpanelkeyplugin'
            }],
            defaults: {
                hideMode: 'offsets'
            },
            activeTab: 0,
            border: false,
            items: [{
            title: this.app.i18n._('Contract'),
            autoScroll: true,
            border: false,
            frame: true,
            layout: 'border',
            items: [{
                region: 'center',
                layout: 'hfit',
                border: false,
                items: [{
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.app.i18n._('Contract'),
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        items: [[
                            {xtype: 'datefield', name: 'start_date', fieldLabel: this.app.i18n._('Start Date'), allowBlank: false },
                            {xtype: 'extuxclearabledatefield', name: 'end_date',   fieldLabel: this.app.i18n._('End Date')},
                            {
                                xtype: 'tinewidgetscontainerselectcombo', 
                                name: 'feast_calendar_id',
                                containerName: this.app.i18n._('Calendar'),
                                containersName: this.app.i18n._('Calendars'),
                                appName: 'Calendar',
                                requiredGrant: 'readGrant',
                                hideTrigger2: true,
                                allowBlank: false,
                                blurOnSelect: true,
                                fieldLabel: this.app.i18n._('Feast Calendar')
                            }
                        ]]
                    }]
                }, {
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.app.i18n._('Working Time'),
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        items: [
                        [
                                Tine.widgets.form.RecordPickerManager.get('HumanResources', 'WorkingTime', {
                                    value: this.record,
                                    fieldLabel: this.app.i18n._('Choose the template'),
                                    selectedRecord: this.record,
                                    ref: '../../../../../../../templateChooser',
                                    columnWidth: 1/3,
                                    name: 'workingtime_template',
                                    listeners: {
                                        scope:  this,
                                        select: this.updateTemplate.createDelegate(this)
                                    }
                                }), {
                                    fieldLabel: this.app.i18n._('Working Hours per week'),
                                    xtype: 'displayfield',
                                    style: { border: 'silver 1px solid', padding: '3px', height: '11px'},
                                    minValue: 1,
                                    decimalPrecision: 2,
                                    decimalSeparator: Tine.Tinebase.registry.get('decimalSeparator'),
                                    name: 'working_hours',
                                    columnWidth: 1/3
                                },{name: 'vacation_days', fieldLabel: this.app.i18n._('Vacation days of one calendar year'), columnWidth: 1/3, allowBlank: false}
                            ],
                            
                            [Ext.apply({
                                fieldLabel: this.app.i18n._('Mon.'),
                                name: 'weekdays_0'
                            }, weekdayFieldDefaults), Ext.apply({
                                fieldLabel: this.app.i18n._('Tue.'),
                                name: 'weekdays_1'
                            }, weekdayFieldDefaults), Ext.apply({
                                fieldLabel: this.app.i18n._('Wed.'),
                                name: 'weekdays_2'
                            }, weekdayFieldDefaults), Ext.apply({
                                fieldLabel: this.app.i18n._('Thu.'),
                                name: 'weekdays_3'
                            }, weekdayFieldDefaults), Ext.apply({
                                fieldLabel: this.app.i18n._('Fri.'),
                                name: 'weekdays_4'
                            }, weekdayFieldDefaults), Ext.apply({
                                fieldLabel: this.app.i18n._('Sat.'),
                                name: 'weekdays_5'
                            }, weekdayFieldDefaults), Ext.apply({
                                fieldLabel: this.app.i18n._('Sun.'),
                                name: 'weekdays_6'
                            }, weekdayFieldDefaults)]
                        ]
                    }]
                }]
            }]
        }]
        };
    },
    
    updateTemplate: function(combo, record, index) {
        this.applyJsonData(Ext.decode(record.get('json')));
    }
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.EmployeeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Employee Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.EmployeeEditDialog
 */
Tine.HumanResources.EmployeeEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    evalGrants: false,
    
    windowWidth: 800,
    windowHeight: 670,
    
    /**
     * show private Information (autoset due to rights)
     * 
     * @type {Boolean}
     */
    showPrivateInformation: null,
    /**
     * inits the component
     */
    initComponent: function() {
        this.showPrivateInformation = (Tine.Tinebase.common.hasRight('edit_private','HumanResources')) ? true : false;
        this.useSales = Tine.Tinebase.appMgr.get('Sales') ? true : false;
        Tine.HumanResources.EmployeeEditDialog.superclass.initComponent.call(this);
        this.on('updateDependent', function() {
            this.disableFreetimes();
        }, this);
    },

    /**
     * updates the display name on change of n_given or n_fanily
     */
    updateDisplayName: function() {
        var nfn = this.getForm().findField('n_given').getValue() + (this.getForm().findField('n_family').getValue() ? ' ' + this.getForm().findField('n_family').getValue() : '');
        this.getForm().findField('n_fn').setValue(nfn);
    },
    
    /**
     * checks if the freetime grids should be disabled
     * 
     * @return {Boolean}
     */
    checkDisableFreetimes: function() {
        // if user is not allowed to see private information, disable the grids
        if (! this.showPrivateInformation) {
            return true;
        }
        
        if (! this.record) {
            return true;
        }
        var c = this.record.get('contracts');
        
        if (Ext.isArray(c) && c.length > 0) {
            // any of the contracts has an id
            for (var index = 0; index < c.length; index++) {
                if (c[index].id) return false;
            }
        }
        
        return true;
    },
    
    /**
     * disable freetime gridpanels if neccessary
     */
    disableFreetimes: function() {
        if (this.checkDisableFreetimes()) {
            this.vacationGridPanel.disable();
            this.sicknessGridPanel.disable();
        } else {
            this.vacationGridPanel.enable();
            this.sicknessGridPanel.enable();
        }
    },
    
    onAfterRecordLoad: function() {
        Tine.HumanResources.EmployeeEditDialog.superclass.onAfterRecordLoad.call(this);
        this.disableFreetimes();
        if (this.record.get('id') && (! Ext.isObject(this.record.get('account_id')))) {
            var f = this.getForm().findField('account_id');
            f.disable();
            f.setRawValue(this.app.i18n._('Account is disabled or deleted!'));
        }
    },
    
    /**
     * returns dialog
     * 
     * NOTE: when this method gets called, all initalisation is done.
     * 
     * @return {Object}
     * @private
     */
    getFormItems: function() {
        var formFieldDefaults = {
            xtype:'textfield',
            anchor: '100%',
            labelSeparator: '',
            columnWidth: .333
        };
        
        var firstRow = [
            Tine.widgets.form.RecordPickerManager.get('HumanResources', 'Employee', {
                allowLinkingItself: false,
                name: 'supervisor_id',
                fieldLabel: this.app.i18n._('Supervisor'),
                editDialog: this,
                allowBlank: true
            })];
            
        if (this.useSales) {
            firstRow.push(Tine.widgets.form.RecordPickerManager.get('Sales', 'Division', {
                    name: 'division_id',
                    fieldLabel: this.app.i18n._('Division'),
                    allowBlank: true
            }));
        }
        
        firstRow.push({
            name: 'health_insurance',
            fieldLabel: this.app.i18n._('Health Insurance'),
            allowBlank: true,
            maxLength: 128
        });

        this.contractGridPanel = new Tine.HumanResources.ContractGridPanel({
            app: this.app,
            editDialog: this,
            disabled: ! this.showPrivateInformation,
            frame: false,
            border: true,
            autoScroll: true,
            layout: 'border'
        });
        
        this.vacationGridPanel = new Tine.HumanResources.FreeTimeGridPanel({
            app: this.app,
            editDialog: this,
            disabled: this.checkDisableFreetimes(),
            frame: false,
            border: true,
            autoScroll: true,
            layout: 'border',
            freetimeType: 'VACATION',
            editDialogRecordProperty: 'vacation'
        });
        this.sicknessGridPanel = new Tine.HumanResources.FreeTimeGridPanel({
            app: this.app,
            editDialog: this,
            disabled: this.checkDisableFreetimes(),
            frame: false,
            border: true,
            autoScroll: true,
            layout: 'border',
            freetimeType: 'SICKNESS',
            editDialogRecordProperty: 'sickness'
        });
            
        var tabs = [{
            title: this.app.i18n._('Employee'),
            autoScroll: true,
            border: false,
            frame: true,
            layout: 'border',
            items: [{
                region: 'center',
                layout: 'hfit',
                border: false,
                items: [{
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.app.i18n._('Employee'),
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        formDefaults: formFieldDefaults,
                        items: [[{
                                fieldLabel: this.app.i18n._('Number'),
                                name: 'number',
                                allowBlank: false,
                                columnWidth: .125,
                                xtype: 'numberfield',
                                maxValue: 999999999
                            }, 
                                Tine.widgets.form.RecordPickerManager.get('Addressbook', 'Contact', {
                                    userOnly: true,
                                    useAccountRecord: true,
                                    blurOnSelect: true,
                                    name: 'account_id',
                                    fieldLabel: this.app.i18n._('Account'),
                                    columnWidth: .380,
                                    ref: '../../../../../../../contactPicker',
                                    allowBlank: false,
                                    listeners: {
                                        scope: this,
                                        blur: function() { 
                                            if (this.contactPicker.selectedRecord) {
                                                this.contactButton.enable();
                                            } else {
                                                this.contactButton.disable();
                                            }
                                        }
                                    }
                                }), {
                               columnWidth: .045,
                               xtype:'button',
                               ref: '../../../../../../../contactButton',
                               iconCls: 'applyContactData',
                               tooltip: Ext.util.Format.htmlEncode(this.app.i18n._('Apply contact data on form')),
                               disabled: (this.record && Ext.isObject(this.record.get('account_id'))) ? false : true,
                               fieldLabel: '&nbsp;',
                               lazyLoading: false,
                               listeners: {
                                    scope: this,
                                    click: function() {
                                        var sr = this.contactPicker.selectedRecord || new Tine.Addressbook.Model.Contact(this.record.data.account_id.contact_id);
                                        if (sr) {
                                            Ext.each(['n_fn', 'title', 'salutation', 'n_given', 'n_family'], function(f) {
                                                this.form.findField(f).setValue(sr.get(f));
                                            }, this);
                                            
                                            if (this.showPrivateInformation) {
                                                this.form.findField('bank_account_holder').setValue(sr.get('n_fn'));
                                                Ext.each(['countryname', 'locality', 'postalcode', 'region', 'street', 'street2'], function(f){
                                                    this.form.findField(f).setValue(sr.get('adr_two_' + f));
                                                }, this);
                                                
                                                Ext.each(['email_home', 'tel_home', 'tel_cell', 'bday'], function(f){
                                                    this.form.findField(f).setValue(sr.get(f));
                                                }, this);
                                            }
                                        }
                                    }
                               }
                            }, {
                                columnWidth: .450,
                                allowBlank: false,
                                fieldLabel: this.app.i18n._('Full Name'),
                                name: 'n_fn',
                                disabled: true
                            }], [
                            new Tine.Tinebase.widgets.keyfield.ComboBox({
                                fieldLabel: this.app.i18n._('Salutation'),
                                name: 'salutation',
                                app: 'Addressbook',
                                keyFieldName: 'contactSalutation',
                                value: '',
                                columnWidth: .25
                            }), {
                                columnWidth: .25,
                                fieldLabel: this.app.i18n._('Title'),
                                name: 'title'
                            }, {
                                columnWidth: .25,
                                fieldLabel: this.app.i18n._('First Name'),
                                name: 'n_given',
                                allowBlank: false,
                                listeners: {
                                    scope: this,
                                    blur: this.updateDisplayName
                                }
                            }, {
                                columnWidth: .25,
                                fieldLabel: this.app.i18n._('Last Name'),
                                name: 'n_family',
                                allowBlank: false,
                                listeners: {
                                    scope: this,
                                    blur: this.updateDisplayName
                                }
                            }]
                        ]
                    }]
                }, {
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.app.i18n._('Personal Information'),
                    disabled: ! this.showPrivateInformation,
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        formDefaults: Ext.apply(Ext.decode(Ext.encode(formFieldDefaults)), {disabled: ! this.showPrivateInformation, readOnly: ! this.showPrivateInformation}),
                        items: [
                            [{
                                xtype: 'widget-countrycombo',
                                name: 'countryname',
                                fieldLabel: this.app.i18n._('Country')
                            }, {
                                name: 'locality',
                                fieldLabel: this.app.i18n._('Locality')
                            }, {
                                name: 'postalcode',
                                fieldLabel: this.app.i18n._('Postalcode')
                            }], [{
                                name: 'region',
                                fieldLabel: this.app.i18n._('Region')
                            }, {
                                name: 'street',
                                fieldLabel: this.app.i18n._('Street')
                            }, {
                                name: 'street2',
                                fieldLabel: this.app.i18n._('Street2')
                            }], [{
                                name: 'email',
                                fieldLabel: this.app.i18n._('E-Mail')
                            }, {
                                name: 'tel_home',
                                fieldLabel: this.app.i18n._('Telephone Number')
                            }, {
                                name: 'tel_cell',
                                fieldLabel: this.app.i18n._('Cell Phone Number')
                            }], [{
                                xtype: 'extuxclearabledatefield',
                                name: 'bday',
                                fieldLabel: this.app.i18n._('Birthday')
                            }
                        ]]
                    }]
                }, {
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.app.i18n._('Internal Information'),
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        formDefaults: Ext.apply(Ext.decode(Ext.encode(formFieldDefaults)), {}),
                        items: [ firstRow
                            , [{
                                xtype: 'datefield',
                                name: 'employment_begin',
                                fieldLabel: this.app.i18n._('Employment begin'),
                                allowBlank: false,
                                columnWidth: .5
                            }, {
                                xtype: 'extuxclearabledatefield',
                                name: 'employment_end',
                                allowBlank: true,
                                fieldLabel: this.app.i18n._('Employment end'),
                                columnWidth: .5
                            }, {
                                name: 'profession',
                                fieldLabel: this.app.i18n._('Profession'),
                                columnWidth: .5
                            }, {
                                name: 'position',
                                fieldLabel: this.app.i18n._('Position'),
                                columnWidth: .5
                            }
                        ]]
                    }]
                }, {
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.app.i18n._('Banking Information'),
                    disabled: ! this.showPrivateInformation,
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        formDefaults: Ext.apply(Ext.decode(Ext.encode(formFieldDefaults)), {disabled: ! this.showPrivateInformation, readOnly: ! this.showPrivateInformation}),
                        items: [
                            [{
                                name: 'bank_account_holder',
                                fieldLabel: this.app.i18n._('Account Holder')
                            }, {
                                name: 'bank_account_number',
                                fieldLabel: this.app.i18n._('Account Number')
                            }, {
                                name: 'bank_name',
                                fieldLabel: this.app.i18n._('Bank Name')
                            }], [{
                                name: 'bank_code_number',
                                fieldLabel: this.app.i18n._('Code Number')
                            }, {
                                name: 'iban',
                                fieldLabel: 'IBAN'
                            }, {
                                name: 'bic',
                                fieldLabel: 'BIC'
                            }
                        ]]
                    }]
                }
                
                ]
            }, {
                // activities and tags
                layout: 'accordion',
                animate: true,
                region: 'east',
                width: 210,
                split: true,
                collapsible: true,
                collapseMode: 'mini',
                header: false,
                margins: '0 5 0 5',
                border: true,
                items: [
                    new Ext.Panel({
                        title: this.app.i18n._('Description'),
                        iconCls: 'descriptionIcon',
                        layout: 'form',
                        labelAlign: 'top',
                        border: false,
                        items: [{
                            style: 'margin-top: -4px; border 0px;',
                            labelSeparator: '',
                            xtype: 'textarea',
                            name: 'description',
                            hideLabel: true,
                            grow: false,
                            preventScrollbars: false,
                            anchor: '100% 100%',
                            emptyText: this.app.i18n._('Enter description'),
                            requiredGrant: 'editGrant'
                        }]
                    }),
                    new Tine.widgets.tags.TagPanel({
                        app: 'HumanResources',
                        border: false,
                        bodyStyle: 'border:1px solid #B5B8C8;'
                    })
                ]
            }]
        }];
        
        if (this.useSales) {
            this.costCenterGridPanel = new Tine.HumanResources.CostCenterGridPanel({
                app: this.app,
                editDialog: this,
                disabled: ! this.showPrivateInformation
            });
            tabs.push(this.costCenterGridPanel);
        }
        
        tabs = tabs.concat([
            this.contractGridPanel,
            this.vacationGridPanel,
            this.sicknessGridPanel,
            new Tine.widgets.activities.ActivitiesTabPanel({
                app: this.appName,
                record_id: this.record.id,
                record_model: 'HumanResources_Model_Employee'
            })
        ]);
        
        return {
            xtype: 'tabpanel',
            defaults: {
                hideMode: 'offsets'
            },
            border: false,
            plain: true,
            activeTab: 0,
            items: tabs
        };
    }
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2016 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.FreeTimeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>DatePicker with multiple days</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * Create a new Tine.HumanResources.DatePicker
 */
Tine.HumanResources.DatePicker = Ext.extend(Ext.DatePicker, {
    
    recordClass: null,
    app: null,
    
    /**
     * the employee to use for this freetime
     * 
     * @type {Tine.HumanResources.Model.Employee}
     */
    employee: null,
    
    /**
     * dates higlighted as vacation day
     * 
     * @type {Array}
     */
    vacationDates: null,
    
    /**
     * dates higlighted as feast day
     * 
     * @type {Array}
     */
    feastDates : null,
    
    /**
     * dates higlighted as sickness day
     * 
     * @type {Array}
     */
    sicknessDates: null,
    
    /**
     * holds the freetime type (SICKNESS or VACATION)
     * 
     * @type {String}
     */
    freetimeType: null,
    
    /**
     * the editdialog this is nested in
     * 
     * @type {Tine.HumanResources.FreeTimeEditDialog}
     */
    editDialog: null,
    
    /**
     * if vacation is handled, the account picker of the edit dialog is active
     * 
     * @type {Boolean}
     */
    accountPickerActive: null,
    
    dateProperty: 'date',
    recordsProperty: 'freedays',
    foreignIdProperty: 'freetime_id',
    useWeekPickerPlugin: false,
    
    /**
     * holds the previous year selected (to switch back on no account found exception
     * 
     * @type {Number}
     */
    previousYear: null,
    
    /**
     * holds the current year selected
     * 
     * @type {Number}
     */
    currentYear: null,

    /**
     * used to enable/disable checks in update()
     */
    initializing: true,
    
    /**
     * initializes the component
     */
    initComponent: function() {
        if (this.useWeekPickerPlugin) {
            this.plugins = this.plugins ? this.plugins : [];
            this.plugins.push(new Ext.ux.DatePickerWeekPlugin({
                weekHeaderString: Tine.Tinebase.appMgr.get('Calendar').i18n._('WK')
            }));
        }
        
        this.vacationDates = [];
        this.sicknessDates = [];
        this.feastDates    = [];
        
        this.initStore();

        Tine.HumanResources.DatePicker.superclass.initComponent.call(this);
    },
    
    /**
     * initializes the store
     */
    initStore: function() {
        Tine.log.debug('Initializing the store...');
        var picker = this;
        this.store = new Tine.Tinebase.data.RecordStore({
            remoteSort: false,
            recordClass: this.recordClass,
            autoSave: false,
            getByDate: function(date) {
                if (!Ext.isDate(date)) {
                    date = new Date(date);
                }
                var index = this.findBy(function(record) {
                    if(record.get(picker.dateProperty).toString() == date.toString()) {
                        return true;
                    }
                });
                return this.getAt(index);
            },
            getFirstDay: function() {
                this.sort('date', 'ASC');
                return this.getAt(0);
            },
            
            getLastDay: function() {
                this.sort('date', 'ASC');
                return this.getAt(this.getCount() - 1);
            }
        }, this);
    },
    
    /**
     * loads the feast days of the configured feast calendar from the server
     * 
     * @param {Boolean} fromYearChange
     * @param {Boolean} onInit
     * @param {Date} date
     * @param {Number} year
     */
    loadFeastDays: function(fromYearChange, onInit, date, year) {
        
        Tine.log.debug('Loading feast and freedays, using the year ' + year);
        
        this.disableYearChange = fromYearChange;
        
        var employeeId = this.editDialog.fixedFields.get('employee_id').id;
        var freeTimeId = this.editDialog.record.get('id') ? this.editDialog.record.get('id') : null;
        var accountId  = this.editDialog.record.get('account_id') ? this.editDialog.record.get('account_id').id : null;
        this.loadMask = new Ext.LoadMask(this.getEl(), {
            msg: this.app.i18n._('Loading calendar data...')
        });
        
        this.loadMask.show();
        
        var that = this;
        
        Ext.Ajax.request({
            url : 'index.php',
            params : { 
                method:      'HumanResources.getFeastAndFreeDays', 
                _employeeId: employeeId, 
                _year:       year, 
                _freeTimeId: freeTimeId,
                _accountId:  accountId
            },
            success : function(_result, _request) {
                that.onFeastDaysLoad(Ext.decode(_result.responseText), onInit, date, year);
            },
            failure : function(exception) {
                Tine.log.debug('Loading feast and freedays failed with the exception:', exception);
                Tine.Tinebase.ExceptionHandler.handleRequestException(exception, that.onFeastDaysLoadFailureCallback, that);
            },
            scope: that
        });
    },
    
    /**
     * loads the feast days from loadFeastDays
     * 
     * @param {Object} result
     * @param {Boolean} onInit
     * @param {Date} date
     * @param {Number} year
     */
    onFeastDaysLoad: function(result, onInit, date, year) {
        Tine.log.debug('Loaded feast and freedays for the year ' + year + ':');
        var rr = result.results;
        Tine.log.debug(rr);
        Tine.log.debug(result);

        this.initializing = onInit;

        this.disabledDates = [];
        //  days not to work on by contract
        var exdates = rr.excludeDates || [];
        var freetime = this.editDialog.record;
        
        // format dates to fit the datepicker format
        Ext.each(exdates, function(d) {
            Ext.each(d, function(date) {
                // TODO invent helper function for this date splitting stuff
                var split = date.date.split(' '), dateSplit = split[0].split('-');
                var disabledDate = new Date(dateSplit[0], dateSplit[1] - 1, dateSplit[2]);
                this.disabledDates.push(disabledDate);
            }, this);
        }, this);

        this.setVacationDates(this.editDialog.localVacationDays);
        this.setSicknessDates(this.editDialog.localSicknessDays);
        this.setFeastDates(rr.feastDays);

        this.setDisabledDates(this.disabledDates);
        
        this.updateCellClasses();
        
        var split = rr.firstDay.date.split(' '), dateSplit = split[0].split('-');
        var firstDay = new Date(dateSplit[0], dateSplit[1] - 1, dateSplit[2]);
        this.setMinDate(firstDay);
        
        var split = rr.lastDay.date.split(' '), dateSplit = split[0].split('-');
        var lastDay = new Date(dateSplit[0], dateSplit[1] - 1, dateSplit[2]);
        // allow too book last years leftover holidays
        lastDay.setFullYear(lastDay.getFullYear() + 1);
        this.setMaxDate(lastDay);
        
        // if ownFreeDays is empty, the record hasn't been saved already, so use the properties from the local record
        var iterate = (rr.ownFreeDays && rr.ownFreeDays.length > 0) ? rr.ownFreeDays : (freetime ? freetime.get('freedays') : null);
        
        if (Ext.isArray(iterate)) {
            Ext.each(iterate, function(fd) {
                // TODO check cases when fd.date has no split()
                if (Ext.isFunction(fd.date.split)) {
                    var split = fd.date.split(' '), dateSplit = split[0].split('-');
                    fd.date = new Date(dateSplit[0], dateSplit[1] - 1, dateSplit[2]);
                    fd.date.clearTime();
                    this.store.add(new this.recordClass(fd));
                }
            }, this);
        }

        if (this.accountPickerActive && onInit) {
            // set remaining vacation days in edit dialog
            // TODO this should be refactored and moved to edit dialog as this is an unexpected place here
            var substractDays = this.editDialog.getDaysToSubstract();
            this.editDialog.getForm().findField('remaining_vacation_days').setValue(rr.allVacation - substractDays);
        }
        
        this.updateCellClasses();
        this.loadMask.hide();

        if (onInit) {
            this.previousYear = this.currentYear;
            this.currentYear = parseInt(rr.firstDay.date.split('-')[0]);
        }

        var focusDate = freetime.get('firstday_date');
        if (date) {
            focusDate = date;
        } else if (this.disableYearChange) {
            if (this.previousYear < this.currentYear) {
                focusDate = new Date(this.currentYear + '/01/01 12:00:00 AM');
            } else {
                focusDate = new Date(this.currentYear + '/12/31 12:00:00 AM');
            }
        }

        // disableYearChange here to make sure we don't load feast and free days again during update() or enable()
        // TODO this needs to be refactored!!
        this.disableYearChange = true;

        // focus
        if (focusDate) {
            Tine.log.debug('focusDate ' + focusDate + ' currentYear ' + this.currentYear);
            this.update(focusDate);
        }

        this.enable();
        
        this.disableYearChange = false;
    },
    
    /**
     * if loading feast and freedays fails
     */
    onFeastDaysLoadFailureCallback: function() {
        
        Tine.log.debug('Calling onFeastDaysLoadFailureCallback with current year ' + this.currentYear + ' and previous year ' + this.previousYear);
        
        var year = this.currentYear;
        this.currentYear = this.previousYear;
        this.previousYear = year;
        this.onYearChange();
    },
    
    /**
     * set vacation dates
     * 
     * @param {Object} localVacationDays
     * @param {Array} remoteVacationDays
     * @param {Object} locallyRemovedDays
     */
    setVacationDates: function(localVacationDays, remoteVacationDays, locallyRemovedDays) {
        this.vacationDates = this.getTimestampsFromDays(localVacationDays, remoteVacationDays, locallyRemovedDays);
    },
    
    /**
     * set sickness dates
     * 
     * @param {Object} localSicknessDays
     * @param {Array} remoteSicknessDays
     * @param {Object} locallyRemovedDays
     */
    setSicknessDates: function(localSicknessDays, remoteSicknessDays, locallyRemovedDays) {
        this.sicknessDates = this.getTimestampsFromDays(localSicknessDays, remoteSicknessDays, locallyRemovedDays);
    },
    
    /**
     * set feast dates
     */
    setFeastDates: function(feastDays) {
        this.feastDates = this.getTimestampsFromDays([], feastDays);
    },
    
    /**
     * returns a timestamp from a day
     * 
     * @param {Object} localDays
     * @param {Array} remoteDays
     * @param {Object} locallyRemovedDays
     * 
     * @return {Array}
     */
    getTimestampsFromDays: function(localDays, remoteDays, locallyRemovedDays) {
        
        var dates = [];
        Ext.iterate(localDays, function(accountId, localdates) { 
            for (var index = 0; index < localdates.length; index++) {
                var newdate = new Date(localdates[index].date.replace(/-/g,'/') + ' AM');
                newdate.setHours(0);
                dates.push((newdate.getTime()));
            }
        });
        
        // find out removed dates
        var remove = [];
        if (locallyRemovedDays) {
            Ext.iterate(locallyRemovedDays, function(accountId, removeDays) {
                for (var index = 0; index < removeDays.length; index++) {
                    remove.push(removeDays[index].date.split(' ')[0]);
                }
            }, this);
        }
        
        // do not mark day as taken, if it is deleted already in the grid
        if (remoteDays) {
            for (var index = 0; index < remoteDays.length; index++) {
                var day = remoteDays[index].date.split(' ')[0];
                if (remove.indexOf(day) == -1) {
                    var newdate = new Date(remoteDays[index].date.replace(/-/g,'/') + ' AM');
                    dates.push(newdate.getTime());
                }
            }
        }
        
        return dates;
    },
    
    /**
     * is called on year change
     *
     * @param {Date} date
     */
    onYearChange: function(date) {
        Tine.log.debug('Calling onYearChange with the date ' + date);
        // this is called on changing the year in the picker
        this.loadFeastDays(true, false, date, date.format('Y'));
    },
    
    /**
     * overwrites update function of superclass
     * 
     * @param {Date} date
     * @param {Boolean} forceRefresh
     */
    update : function(date, forceRefresh) {
        Tine.HumanResources.DatePicker.superclass.update.call(this, date, forceRefresh);
        
        if (! this.disableYearChange && ! this.initializing) {
            var year = parseInt(date.format('Y'));
            if (year !== this.currentYear) {
                if (this.getData().length > 0) {
                    Ext.MessageBox.show({
                        title: this.app.i18n._('Year can not be changed'),
                        msg: this.app.i18n._('You have already selected some dates from another year. Please create a new record to add dates from another year!'),
                        buttons: Ext.Msg.OK,
                        icon: Ext.MessageBox.WARNING,
                        // jump to the first day of the selected
                        fn: function () {
                            var firstDay = this.store.getFirstDay();
                            this.update(firstDay.get('date'));
                        },
                        scope: this
                    });
                } else {
                    this.previousYear = this.currentYear;
                    this.currentYear = parseInt(date.format('Y'));
                    this.onYearChange(date);
                }
            }
        }
        
        this.updateCellClasses();
    },

    /**
     * removes or adds a date on date click
     * 
     * @param {Object} e
     * @param {Object} t
     */
    handleDateClick: function(e, t) {
        // don't handle date click, if this is disabled, or the clicked node doesn't have a timestamp assigned
        if (this.disabled || ! t.dateValue) {
            return Tine.HumanResources.DatePicker.superclass.handleDateClick.call(this, e, t);
        }
        // don't handle click on disabled dates defined by contract or feast calendar
        if (Ext.fly(t.parentNode).hasClass('x-date-disabled')) {
            return Tine.HumanResources.DatePicker.superclass.handleDateClick.call(this, e, t);
        }
        
        // dont't handle click on already defined sickness days
        if (Ext.fly(t.parentNode).hasClass('hr-date-sickness')) {
            return Tine.HumanResources.DatePicker.superclass.handleDateClick.call(this, e, t);
        }
        
        // dont't handle click on feast days
        if (Ext.fly(t.parentNode).hasClass('hr-date-feast')) {
            return;
        }
        
        // dont't handle click on already defined vacation days from different vacation entries
        if (Ext.fly(t.parentNode).hasClass('hr-date-vacation') &&
           !Ext.fly(t.parentNode).hasClass('x-date-selected')) {
            return;
        }
        
        var date = new Date(t.dateValue),
            existing = this.store.getByDate(date);
            
        date.clearTime();
        
        if (this.accountPickerActive) {

            var remaining = this.editDialog.getForm().findField('remaining_vacation_days').getValue();

            if (existing) {
                remaining++;
            } else {
                remaining--;
            }

            if (remaining < 0) {
                Ext.MessageBox.show({
                    title: this.app.i18n._('No more vacation days'),
                    msg: this.app.i18n._('The Employee has no more possible vacation days left for this year. Create a new vacation and use another personal account the vacation should be taken from.'),
                    icon: Ext.MessageBox.WARNING,
                    buttons: Ext.Msg.OK
                });
                return Tine.HumanResources.DatePicker.superclass.handleDateClick.call(this, e, t);
            }
        } else {
            var remaining = 0;
        }

        if (existing) {
            this.store.remove(existing);
            var index = this.vacationDates.indexOf(t.dateValue);
            if (index > -1) {
                this.vacationDates.splice(index, 1);
            }
        } else {
            this.store.addSorted(new this.recordClass({date: date, duration: 1}));
        }
        
        if (this.accountPickerActive) {
            if (this.store.getCount() > 0) {
                this.editDialog.accountPicker.disable();
            } else {
                this.editDialog.accountPicker.enable();
            }

            this.editDialog.getForm().findField('remaining_vacation_days').setValue(remaining);
        }
        
        Tine.HumanResources.DatePicker.superclass.handleDateClick.call(this, e, t);
    },
    
    /**
     * updates the cell classes
     */
    updateCellClasses: function() {
        
        this.cells.each(function(c) {
            
            var timestamp = c.dom.firstChild.dateValue;
            
            if (this.store.getByDate(timestamp)) {
                c.addClass('x-date-selected');
            } else {
                c.removeClass('x-date-selected');
                if (c.hasClass('hr-date-vacation')) {
                    c.removeClass('hr-date-vacation');
                }
            }
            
            if (this.vacationDates.indexOf(timestamp) > -1) {
                c.addClass('hr-date-vacation');
            }
            
            if (this.sicknessDates.indexOf(timestamp) > -1) {
                c.addClass('hr-date-sickness');
            }
            
            if (this.feastDates.indexOf(timestamp) > -1) {
                c.addClass('hr-date-feast');
            }
           
        }, this);
    },
    
    /**
     * returns data for the editDialog
     * 
     * @return {Array}
     */
    getData: function() {
        var ret = [];
        this.store.sort({field: 'date', direction: 'ASC'});
        this.store.query().each(function(record) {
            ret.push(record.data);
        }, this);
        
        return ret;
    }
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * FreeDay grid panel
 * 
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.FreeDayGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 * 
 * <p>FreeDay Grid Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>    
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.FreeDayGridPanel
 */
Tine.HumanResources.FreeDayGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.FreeTimeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>FreeTime Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * Create a new Tine.HumanResources.FreeTimeEditDialog
 */
Tine.HumanResources.FreeTimeEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    mode: 'local',
    
    /**
     * show private Information (autoset due to rights)
     * 
     * @type {Boolean}
     */
    showPrivateInformation: null,
    
    /**
     * holds cached getFeastAndFreeDaysQueries
     * 
     * @type {Array}
     */
    calculatedFeastDays: null,
    
    /**
     * either SICKNESS or VACATION
     * 
     * @type {String}
     */
    freetimeType: null,
    
    /**
     * the datepicker holds a calendar to select the dates of vacation or sickness
     * 
     * @type {Tine.HumanResources.DatePicker}
     */
    datePicker: null,
    
    /**
     * the account picker holds the account the (vacation-)days are taken from
     * @type {Tine.Tinebase.widgets.form.RecordPickerComboBox}
     */
    accountPicker: null,
    
    /**
     * two years ago for the accountPicker search
     * 
     * @type {Number}
     */
    twoYearsAgo: null,
    
    /**
     * year on init time
     * 
     * @type {Number}
     */
    startYear: null,
    
    /**
     * holds the current account (by the startYear, if no account is given by the record)
     * 
     * @type {Tine.HumanResources.Model.Account}
     */
    currentAccount: null,
    
    /**
     * overwrite update toolbars function (we don't have record grants yet)
     * @private
     */
    updateToolbars: Ext.emptyFn,
    
    /**
     * holds vacation day records already inserted in the employee by account_id
     * 
     * @type {Object}
     */
    localVacationDays: null,
    
    /**
     * holds already removed sickness days which are not persisted
     * 
     * @type {Object}
     */
    removedSicknessDays: null,
    
    /**
     * holds already removed vacation days which are not persisted
     * 
     * @type {Object}
     */
    removedVacationDays: null,
    
    /**
     * holds sickness day records already inserted in the employee by account_id
     * 
     * @type {Object}
     */
    localSicknessDays: null,
    
    /**
     * inits the component
     */
    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('HumanResources');
        this.showPrivateInformation = (Tine.Tinebase.common.hasRight('edit_private','HumanResources')) ? true : false;
        
        this.calculatedFeastDays = [];
        this.localVacationDays = {};
        this.localSicknessDays = {};
        
        // calculate current year and two years ago for the accountPicker search
        var date = new Date();
        this.startYear = parseInt(date.format('Y'));
        this.twoYearsAgo = this.startYear - 2;
        
        Tine.HumanResources.FreeTimeEditDialog.superclass.initComponent.call(this);
    },
    
    /**
     * executed after record got updated from proxy
     * 
     * @private
     */
    onRecordLoad: function() {
        // interrupt process flow until dialog is rendered
        if (! this.rendered) {
            this.onRecordLoad.defer(250, this);
            return;
        }
        
        if (Ext.isString(this.record)) {
            this.record = this.recordProxy.recordReader({responseText: this.record});
        }
        this.record.set('employee_id', this.fixedFields.get('employee_id'));
        
        if (this.record.get('employee_id')) {
            this.window.setTitle(String.format(i18n._('Edit {0} "{1}"'), this.i18nRecordName, this.record.getTitle()));
        }
        
        Tine.HumanResources.FreeTimeEditDialog.superclass.onRecordLoad.call(this);
        
        if (this.accountPicker) {
            this.accountPicker.onRecordLoad(this.record);
        }
        // set title after record load to determine if it's an update or new record
        var typeString = this.freetimeType == 'SICKNESS' ? 'Sickness Days' : 'Vacation Days';
        if (this.record.id) {
            if (this.accountPicker) {
                this.accountPicker.disable();
            }
            this.window.setTitle(String.format(this.app.i18n._('Edit {0} for {1}'), this.app.i18n._hidden(typeString), this.record.get('employee_id').n_fn));
        } else {
            this.window.setTitle(String.format(this.app.i18n._('Add {0} for {1}'),  this.app.i18n._hidden(typeString), this.record.get('employee_id').n_fn));
            this.statusPicker.setValue((this.freetimeType == 'SICKNESS') ? 'EXCUSED' : 'ACCEPTED');
        }
    },
    
    /**
     * just break if at least one day is selected, otherwise close the window
     * 
     * @param {Boolean} closeWindow
     * @return {Boolean}
     */
    onApplyChanges: function(closeWindow) {
        // if no day is selected, show message and break saving
        if (! this.datePicker.store.getFirstDay()) {
            var msg = this.freetimeType == 'SICKNESS'
                ? this.app.i18n._('You have to select at least one day to save this sickness entry.')
                : this.app.i18n._('You have to select at least one day to save this vacation entry.');
            Ext.MessageBox.show({
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.WARNING,
                title: this.app.i18n._('No day selected'), 
                msg: msg
            });
            
            return false;
        } else {
            Tine.HumanResources.FreeTimeEditDialog.superclass.onApplyChanges.call(this, closeWindow);
        }
    },
    
    /**
     * executed when record gets updated from form
     * @private
     */
    onRecordUpdate: function() {
        Tine.HumanResources.FreeTimeEditDialog.superclass.onRecordUpdate.call(this);
        
        var firstDay = this.datePicker.store.getFirstDay();
        var lastDay  = this.datePicker.store.getLastDay();
        
        // add in json by year if sickness record
        if (! this.accountPicker) {
            this.record.set('account_id', null);
        } else {
            this.record.set('account_id', this.currentAccount.data);
        }
        
        this.record.set('freedays',      this.datePicker.getData());
        this.record.set('type',          this.fixedFields.get('type').toLowerCase());
        this.record.set('firstday_date', new Date(firstDay.get('date')));
        this.record.set('lastday_date',  new Date(lastDay.get('date')));
        this.record.set('days_count',    this.datePicker.store.getCount());
    },
    
    /**
     * creates the date picker
     */
    initDatePicker: function() {
        var date, account = null;
        if (this.record.id && (account = this.record.get('account_id'))) {
            var year = account.year;
        } else {
            var year = this.startYear;
        }
        
        Tine.log.debug('Initializing the date picker. Using year ' + year);
        
        this.datePicker = new Tine.HumanResources.DatePicker({
            accountPickerActive: (this.freetimeType == 'VACATION') ? true : false,
            recordClass: Tine.HumanResources.Model.FreeDay,
            app: this.app,
            editDialog: this,
            dateProperty: 'date',
            recordsProperty: 'freedays',
            foreignIdProperty: 'freeday_id',
            freetimeType: this.freetimeType,
            currentYear: year,
            value: date || new Date(year, 1, 1)
        });
    },
    
    /**
     * validates day length
     * 
     * @param {Float/Integer} value
     * @return {Boolean}
     */
    isDayLengthValid: function(value) {
        return (value <= 1 && value >=0.25);
    },
    
    /**
     * initializes the account picker
     */
    initAccountPicker: function() {
        Tine.log.debug('Initializing the account picker...');
        var that = this;
        
        this.accountPicker = Tine.widgets.form.RecordPickerManager.get('HumanResources', 'Account', {
            name: 'account_id',
            fieldLabel: this.app.i18n._('Personal account'),
            additionalFilters: [
                {field: 'employee_id', operator: 'AND', value: [
                    { field: ':id', operator: 'equals', value: this.fixedFields.get('employee_id').id}
                ]}
            ],
            
            /**
             * fills the accountPicker on init with the account associated to 
             * the record or current year if the record is new
             * 
             * @param {Tine.HumanResources.Model.Account} record
             */
            onRecordLoad: function(record) {
                
                Tine.log.debug('Called onRecordLoad of the account picker...');
                
                if (record.get('account_id')) {
                    Tine.log.debug('The record has an account attached:', record.get('account_id'));
                    
                    that.currentAccount = new Tine.HumanResources.Model.Account(record.get('account_id'));
                    that.datePicker.loadFeastDays(false, true, null, that.currentAccount.get('year'));
                    return;
                }
                
                Tine.log.debug('The record is new, so no account has been attached. So we search one for the year ' + this.startYear);
                
                var addFilters = [{field: 'employee_id', operator: 'AND', value: [
                    { field: ':id', operator: 'equals', value: record.get('employee_id').id}
                ]}, {field: 'year', operator:'equals', value: this.startYear}];
                
                var request = Ext.Ajax.request({
                    url : 'index.php',
                    params : { method : 'HumanResources.searchAccounts', filter: addFilters},
                    success : function(_result, _request) {
                        var result = Ext.decode(_result.responseText);
                        this.store.loadData(result);
                        var rr = result.results;
                        for (var index = 0; index < rr.length; index++) {
                            if (rr[index].year == that.startYear) {
                                this.setValue(rr[index]);
                                that.currentAccount = new Tine.HumanResources.Model.Account(rr[index]);
                                that.datePicker.loadFeastDays(false, true, null, that.currentAccount.get('year'));
                            }
                        }
                    },
                    failure : function(exception) {
                        Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
                    },
                    scope: this
                });
            }
        });
        
        // update remaining days on account change
        this.accountPicker.on('select', function(combo, record, index) {
            var year = record.get('year');
            
            Tine.log.debug('On select event handler called. Using year ' + year);
            
            that.currentAccount = record;
            // if not cached, fetch from server
            if (! that.calculatedFeastDays[year]) {
                Tine.log.debug('No cached feast days found. Creating request...');
                var request = Ext.Ajax.request({
                    url : 'index.php',
                    params : { 
                        method : 'HumanResources.getFeastAndFreeDays',
                        _employeeId: this.fixedFields.get('employee_id').id,
                        _year: year
                    },
                    success : function(_result, _request) {
                        var response = Ext.decode(_result.responseText);
                        // cache result
                        this.calculatedFeastDays[year] = response.results;
                        this.onAccountLoad(response.results);
                        // update date picker
                        this.datePicker.onFeastDaysLoad(response, false, null, year);
                    },
                    failure : function(exception) {
                        Tine.Tinebase.ExceptionHandler.handleRequestException(exception, this.onFeastDaysLoadFailureCallback, this);
                    },
                    scope: that
                });
            } else {
                Tine.log.debug('Cached feast days found for year ' + year);
                that.onAccountLoad(this.calculatedFeastDays[year]);
            }
        }, this);
    },
    
    /**
     * initializes the status picker
     */
    initStatusPicker: function() {
        this.freetimeType = this.fixedFields.get('type');
        
        Tine.log.debug('Initializing status picker with type "' + this.freetimeType + '"');
        
        var statusPickerDefaults = {
            fieldLabel: this.app.i18n._('Status'),
            xtype: 'widget-keyfieldcombo',
            app: 'HumanResources',
            name: 'status'
        };
        if (this.freetimeType != 'VACATION') {
            this.statusPicker = new Tine.Tinebase.widgets.keyfield.ComboBox(
                Ext.apply({
                    keyFieldName: 'sicknessStatus',
                    value: 'EXCUSED',
                    columnWidth: 1
                }, statusPickerDefaults)
            );
        } else {
            this.statusPicker = new Tine.Tinebase.widgets.keyfield.ComboBox(
                Ext.apply({
                    keyFieldName: 'vacationStatus',
                    value: 'REQUESTED',
                    columnWidth: 2/3
                }, statusPickerDefaults)
            );
        }
    },
    
    /**
     * 
     * @param {} calculated
     */
    onAccountLoad: function(calculated) {
        var remaining = calculated.allVacation - this.getDaysToSubstract();
        
        Tine.log.debug('Called onAccountLoad. Calculated ' + remaining + ' remaining feast days.');
        
        this.form.findField('remaining_vacation_days').setValue(remaining);
    },
    
    /**
     * if loading feast and freedays failes
     */
    onFeastDaysLoadFailureCallback: function() {
    },
    
    /**
     * calculates the amount of days to substract for the remaining_vacation_days field
     * 
     * @return {Number}
     */
    getDaysToSubstract: function() {
        var substractDays = 0;
        // find out local free days to substract. this is by account only
        var accountId = this.currentAccount.get('id');
        
        if (this.localVacationDays.hasOwnProperty(accountId)) {
            substractDays = substractDays + this.localVacationDays[accountId].length;
        }
        
        return substractDays;
    },
    
    /**
     * returns dialog
     * 
     * NOTE: when this method gets called, all initalisation is done.
     * 
     * @return {Object}
     * @private
     */
    getFormItems: function() {
        this.initDatePicker();
        if (this.freetimeType == 'VACATION') {
            this.initAccountPicker();
        }
        this.initStatusPicker();
        
        var firstRow = [this.statusPicker];
        
        if (this.freetimeType == 'VACATION') {
            firstRow.push(this.accountPicker);
            firstRow.push({columnWidth: 1/3, name: 'remaining_vacation_days', readOnly: true, fieldLabel: this.app.i18n._('Remaining')});
            var freeTimeTypeName = 'Vacation Days';
        } else {
            var freeTimeTypeName = 'Sickness Days';
        }

        return {
            xtype: 'tabpanel',
            border: false,
            plain:true,
            defaults: {
                hideMode: 'offsets'
            },
            plugins: [{
                ptype : 'ux.tabpanelkeyplugin'
            }],
            activeTab: 0,
            border: false,
            items:[{
                title: this.app.i18n._(freeTimeTypeName),
                autoScroll: true,
                border: false,
                frame: true,
                layout: 'border',
                items: [{
                    region: 'center',
                    layout: 'hfit',
                    border: false,
                    items: [{
                        xtype: 'fieldset',
                        autoHeight: true,
                        title: this.app.i18n._(freeTimeTypeName),
                        items: [{
                            xtype: 'columnform',
                            style: { 'float': 'left', width: '50%', 'min-width': '178px' },
                            labelAlign: 'top',
                            formDefaults: {
                                xtype:'textfield',
                                anchor: '100%',
                                labelSeparator: '',
                                allowBlank: false,
                                columnWidth: 1
                            },
                            items: [
                                firstRow,
                                [{
                                    xtype: 'panel',
                                    cls: 'HumanResources x-form-item',
                                    width: 220,
                                    style: {
                                        'float': 'right',
                                        margin: '0 5px 10px 0'
                                    },
                                    items: [{html: '<label style="display:block; margin-bottom: 5px">' + this.app.i18n._('Select Days') + '</label>'}, this.datePicker]
                                }]
                            ]
                        }]
                    }]
                }, {
                    // activities and tags
                    layout: 'accordion',
                    animate: true,
                    region: 'east',
                    width: 210,
                    split: true,
                    collapsible: true,
                    collapseMode: 'mini',
                    header: false,
                    margins: '0 5 0 5',
                    border: true,
                    items: [
                        new Ext.Panel({
                            title: this.app.i18n._('Description'),
                            iconCls: 'descriptionIcon',
                            layout: 'form',
                            labelAlign: 'top',
                            border: false,
                            items: [{
                                style: 'margin-top: -4px; border 0px;',
                                labelSeparator: '',
                                xtype: 'textarea',
                                name: 'description',
                                hideLabel: true,
                                grow: false,
                                preventScrollbars: false,
                                anchor: '100% 100%',
                                emptyText: this.app.i18n._('Enter description'),
                                requiredGrant: 'editGrant'
                            }]
                        })
                    ]
                }]
            }]
        };
    }
});/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.VacationEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Vacation Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * Create a new Tine.HumanResources.VacationEditDialog
 */
Tine.HumanResources.VacationEditDialog = Ext.extend(Tine.HumanResources.FreeTimeEditDialog, {
    freetimeType: 'VACATION'
});

Tine.HumanResources.VacationEditDialog.openWindow  = function (cfg) {
    var id = (cfg.record && cfg.record.id) ? cfg.record.id : 0;
    var window = Tine.WindowFactory.getWindow({
        width: 440,
        height: 450,
        name: 'VacationEditWindow_' + id,
        contentPanelConstructor: 'Tine.HumanResources.VacationEditDialog',
        contentPanelConstructorConfig: cfg
    });
    return window;
};/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.SicknessEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Sickness Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * Create a new Tine.HumanResources.SicknessEditDialog
 */
Tine.HumanResources.SicknessEditDialog = Ext.extend(Tine.HumanResources.FreeTimeEditDialog, {
    freetimeType: 'SICKNESS'
});

Tine.HumanResources.SicknessEditDialog.openWindow  = function (cfg) {
    var id = (cfg.record && cfg.record.id) ? cfg.record.id : 0;
    var window = Tine.WindowFactory.getWindow({
        width: 440,
        height: 450,
        name: 'SicknessEditWindow_' + id,
        contentPanelConstructor: 'Tine.HumanResources.SicknessEditDialog',
        contentPanelConstructorConfig: cfg
    });
    return window;
};/* 
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
 
Ext.ns('Tine.HumanResources');

/**
 * @class     Tine.HumanResources.ContractDetailsPanel
 * @namespace HumanResources
 * @extends   Tine.widgets.grid.DetailsPanel
 * @author    Alexander Stintzing <a.stintzing@metaways.de>
 */

Tine.HumanResources.ContractDetailsPanel = Ext.extend(Tine.widgets.grid.DetailsPanel, {
    
    app: null,
    
    /**
     * the model configuration
     * @type 
     */
    modelConfig: null,
    
    /**
     * @cfg {Number} defaultHeight
     * default Heights
     */
    defaultHeight: 110,
    
    initComponent: function() {
        Tine.HumanResources.ContractDetailsPanel.superclass.initComponent.call(this);
    },
    
    /**
     * main event details panel
     * 
     * @return {Ext.ux.display.DisplayPanel}
     */
    getSingleRecordPanel: function() {
        if (! this.singleRecordPanel) {
            var mc = this.modelConfig, items = [];
            for (var index = 0; index < mc.fieldKeys.length; index++) {
                var fieldConfig = mc.fields[mc.fieldKeys[index]];
                if (fieldConfig.showInDetailsPanel) {
                    items.push({
                        xtype: 'ux.displayfield',
                        name: fieldConfig.key,
                        fieldLabel: fieldConfig.hasOwnProperty('useGlobalTranslation') ? i18n._(fieldConfig.label) : this.app.i18n._(fieldConfig.label),
                        renderer: Tine.widgets.grid.RendererManager.get(mc.appName, mc.modelName, fieldConfig.key),
                        htmlEncode: false
                    });
                }
            }
            
            this.singleRecordPanel = new Ext.ux.display.DisplayPanel(
                this.wrapPanel(items, 110)
            );
        }
        return this.singleRecordPanel;
    },
    
    /**
     * update event details panel
     * 
     * @param {Tine.Tinebase.data.Record} record
     * @param {Mixed} body
     */
    updateDetails: function(record, body) {
        this.getSingleRecordPanel().loadRecord.defer(100, this.getSingleRecordPanel(), [record]);
    },
    
    /**
     * show default template
     * 
     * @param {Mixed} body
     */
    showDefault: function(body) {
        this.showMulti(this.grid.getSelectionModel());
    }
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.EmployeeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Employee Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.EmployeeEditDialog
 */

Tine.HumanResources.ContractGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    /*
     * config
     */
    editDialogRecordProperty: 'contracts',
    /**
     * the calling editDialog
     * @type {Tine.HumanResources.EmployeeEditDialog}
     */
    editDialog: null,
    usePagingToolbar: false,
    
    /**
     * initializes the component
     */
    initComponent: function() {
        this.title = this.app.i18n.ngettext('Contract', 'Contracts', 2);
        if (this.editDialog) {
            this.bbar = [];
        }

        this.initDetailsPanel();
        
        Tine.HumanResources.ContractGridPanel.superclass.initComponent.call(this);

        if (this.editDialog) {
            this.fillBottomToolbar();
        }
    },
    
    /**
     * @private
     */
    initDetailsPanel: function() {
        this.detailsPanel = new Tine.HumanResources.ContractDetailsPanel({
            modelConfig: this.modelConfig,
            grid: this,
            app: this.app
        });
    },
    /**
     * will be called in Edit Dialog Mode
     */
    fillBottomToolbar: function() {
        this.action_deleteRecord.initialConfig.actionUpdater = function(action) {
            var selection = this.getGrid().getSelectionModel().getSelections();
            if (selection.length != 1) {
                action.disable();
                return;
            } else {
                var record = selection[0];
            }
            if (! record) {
                action.disable();
                return;
            }
            
            if (record.id.length == 13) {
                action.enable();
                return;
            }
            
            action.setDisabled(! (record.get('is_editable') == true)); // may be undefined
        }
        
        var tbar = this.getBottomToolbar();
        tbar.addButton(new Ext.Button(this.action_editInNewWindow));
        tbar.addButton(new Ext.Button(this.action_addInNewWindow));
        tbar.addButton(new Ext.Button(this.action_deleteRecord));
    },
    /**
     * Opens the required EditDialog
     * @param {Object} actionButton the button the action was called from
     * @param {Tine.Tinebase.data.Record} record the record to display/edit in the dialog
     * @param {Array} plugins the plugins used for the edit dialog
     * @return {Boolean}
     */
    onEditInNewWindow: function(button, record, plugins) {
        Tine.HumanResources.ContractGridPanel.superclass.onEditInNewWindow.call(this, button, record, plugins);
    },
    
    /**
     * called when Records have been added to the Store
     */
    onStoreAdd: function(store, records, index) {
        var contract = records[0];
        
        // has a temporary id -> check vacation overlap
        if (contract.id.length == 13) {
            this.checkVacationOverlap(contract);
        }
        
        Tine.HumanResources.ContractGridPanel.superclass.onStoreAdd.call(this, store, records, index);
    },
    
    /**
     * shows message if a previous defined vacation is in the time periodof the added contract
     * 
     * @param {Tine.Sales.Model.Contract} contract
     */
    checkVacationOverlap: function(contract) {
        var startDate = contract.get('start_date');
        var store = this.editDialog.vacationGridPanel.getStore();

        // if vacation grid panel has not been loaded, fetch records from the parent record
        if (store.getCount() == 0) {
            store = new Ext.util.MixedCollection();
            if (this.editDialog.record.data.vacation && this.editDialog.record.data.vacation.length) {
                for (var index = 0; index < this.editDialog.record.data.vacation.length; index++) {
                    store.add(new Tine.HumanResources.Model.FreeDay(this.editDialog.record.data.vacation[index]));
                }
            }
            
        }
        
        var found = false;
        store.each(function(record, index) {
            if (record.get('firstday_date') >= startDate) {
                found = true;
            }
        });
        
        if (found) {
            Ext.MessageBox.show({
                title: this.app.i18n._('Vacation in same period'), 
                msg: this.app.i18n._('There are some vacation days matching the period of the contract you added. After saving this employee, changing the contract is not possible anymore.'),
                buttons: Ext.Msg.OK,
                scope: this,
                icon: Ext.MessageBox.WARNING
            });
        }
    }
});

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.EmployeeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Employee Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.EmployeeEditDialog
 */

Tine.HumanResources.CostCenterGridPanel = Ext.extend(Tine.widgets.grid.QuickaddGridPanel, {
    /*
     * config
     */
    frame: true,
    border: true,
    autoScroll: true,
    layout: 'fit',
    defaultSortInfo: {field: 'start_date', direction: 'DESC'},
    autoExpandColumn: 'cost_center_id',
    quickaddMandatory: 'cost_center_id',
    clicksToEdit: 1,
    enableColumnHide:false,
    enableColumnMove:false,
    enableHdMenu: false,
    recordClass: Tine.HumanResources.Model.CostCenter,
    validate: true,
    /*
     * public
     */
    app: null,
    
    /**
     * the calling editDialog
     * Tine.HumanResources.EmployeeEditDialog
     */
    editDialog: null,
    
    /**
     * initializes the component
     */
    initComponent: function() {
        this.title = this.app.i18n.ngettext('CostCenter', 'CostCenters', 2),
        Tine.HumanResources.CostCenterGridPanel.superclass.initComponent.call(this);
        this.store.sortInfo = this.defaultSortInfo;
        this.on('afteredit', this.onAfterEdit, this);
        this.editDialog.on('load', this.loadRecord, this);
        this.store.sort();
        
        // sync record on these events
        this.store.on('update', this.syncStoreToRecord.createDelegate(this));
        this.store.on('add', this.syncStoreToRecord.createDelegate(this));
        this.store.on('remove', this.syncStoreToRecord.createDelegate(this));
    },
    
    /**
     * 
     * @param {} store
     * @param {} record
     * @param {} operation
     */
    syncStoreToRecord: function(store, record, operation) {
        if (this.editDialog.record) {
            var items = [];
            store.each(function(item) {
                items.push(item.data);
            });
            this.editDialog.record.set('costcenters', items);
        }
    },
    
    /**
     * loads the existing CostCenters into the store
     */
    loadRecord: function() {
        var c = this.editDialog.record.get('costcenters');
        if (Ext.isArray(c)) {
            Ext.each(c, function(ar) {
                this.store.addSorted(new this.recordClass(ar));
            }, this);
        }
    },
    
    /**
     * new entry event -> add new record to store
     * @see Tine.widgets.grid.QuickaddGridPanel
     * @param {Object} recordData
     * @return {Boolean}
     */
    onNewentry: function(recordData) {
        recordData.employee_id = this.editDialog.record.get('id');
        var relatedRecord = this.costcenterQuickadd.store.getById(this.costcenterQuickadd.getValue());
        recordData.cost_center_id = relatedRecord.data;
        this.store.addSorted(new this.recordClass(recordData));
    },
    
    /**
     * returns column model
     * 
     * @return Ext.grid.ColumnModel
     * @private
     */
    getColumnModel: function() {
        this.costCenterEditor = Tine.widgets.form.RecordPickerManager.get('Sales', 'CostCenter', { allowBlank: true});
        this.startdateEditor = new Ext.ux.form.ClearableDateField();
        
        this.costcenterQuickadd = Tine.widgets.form.RecordPickerManager.get('Sales', 'CostCenter', {allowBlank: true});
        
        var columns = [
            {id: 'cost_center_id', dataIndex: 'cost_center_id', type: Tine.Sales.Model.CostCenter, header: this.app.i18n._('Cost Center'),
                 quickaddField: this.costcenterQuickadd, renderer: this.renderCostCenter,
                 editor: this.costCenterEditor, scope: this
            }, {id: 'start_date',renderer: Tine.Tinebase.common.dateRenderer, editor: this.startdateEditor, quickaddField: new Ext.ux.form.ClearableDateField(), dataIndex: 'start_date', header: this.app.i18n._('Startdate'),  scope: this, width: 120}
        ];
        
        
        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                width: 160,
                editable: true
            }, 
            columns: columns
       });
    },
    
    /**
     * is called on after edit to set related records
     * @param {} o
     */
    onAfterEdit: function(o) {
        if (o.field == 'start_date') {
            o.record.set('start_date', this.startdateEditor.getValue());
        } else if (o.field == 'cost_center_id') {
            var relatedRecord = this.costCenterEditor.store.getById(this.costCenterEditor.getValue());
            o.record.set('cost_center_id', relatedRecord.data);
        }
    },
    
    /**
     * renders the cost center
     * @param {Object} value
     * @param {Object} row
     * @param {Tine.Tinebase.data.Record} record
     * 
     * return {String}
     */
    renderCostCenter: function(value, row, record) {
        return '<span class="tine-recordclass-gridicon SalesCostCenter">&nbsp;</span>' + (record ? record.get('cost_center_id').number + ' - ' + record.getTitle() : '');
    }
});

/**
 * Tine 2.0
 * 
 * @package     HumanResources
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
 */
 
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.FreeTimeEmployeeFilterModel
 * @extends     Tine.widgets.grid.ForeignRecordFilter
 * 
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 */
Tine.HumanResources.FreeTimeEmployeeFilterModel = Ext.extend(Tine.widgets.grid.ForeignRecordFilter, {
    
    // private
    ownField: 'employee_id',
    linkType: 'foreignId',
    foreignRecordClass: Tine.HumanResources.Model.Employee,
    filterName: 'EmployeeFilter',
    /**
     * @private
     */
    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('HumanResources');
        this.label = this.app.i18n._('Employee');
        this.pickerConfig = {allowBlank: true };

        Tine.HumanResources.FreeTimeEmployeeFilterModel.superclass.initComponent.call(this);
    }
});

Tine.widgets.grid.FilterToolbar.FILTERS['humanresources.freetimeemployee'] = Tine.HumanResources.FreeTimeEmployeeFilterModel;/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * Account grid panel
 * 
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.AccountGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 * 
 * <p>Account Grid Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>    
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.AccountGridPanel
 */
Tine.HumanResources.AccountGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    
    initComponent: function() {
        this.actions_bookVacation = new Ext.Action({
            text: this.app.i18n._('Book remaining vacation'),
            iconCls: 'action_export',
            allowMultiple: true,
            handler: this.bookRemaining.createDelegate(this)
        });
        
        this.contextMenuItems = [this.actions_bookVacation];
        
        Tine.HumanResources.AccountGridPanel.superclass.initComponent.call(this);
        this.action_addInNewWindow.hide();
        this.action_deleteRecord.hide();
    },
    
    createMissingAccounts: function() {
        Ext.Msg.prompt(this.app.i18n._('Year'), this.app.i18n._('Please enter the year you want to create accounts for:'), function(btn, year) {
            if (btn == 'ok') {
                Ext.Ajax.request({
                    url : 'index.php',
                    timeout: 60000*5,
                    params : { method : 'HumanResources.createMissingAccounts', year: year},
                    success : function(_result, _request) {
                        this.onAccountCreateSuccess(Ext.decode(_result.responseText));
                    },
                    failure : function(exception) {
                        Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
                    },
                    scope: this
                });
            }
        }, this);
    },
    
    onAccountCreateSuccess: function(data) {
        Ext.MessageBox.show({
            buttons: Ext.Msg.OK,
            icon: Ext.MessageBox.INFO,
            title: this.app.i18n._('Accounts have been created'), 
            msg: String.format(this.app.i18n._('{0} accounts for the year {1} have been created successfully!'), data.totalcount, data.year)
        });
    },
    
    /**
     * returns additional toobar items
     * 
     * @return {Array} of Ext.Action
     */
    getActionToolbarItems: function() {
        this.actions_createAccounts = new Ext.Action({
            text: this.app.i18n._('Create new accounts'),
            iconCls: 'action_create_accounts',
            allowMultiple: true,
            handler: this.createMissingAccounts.createDelegate(this)
        });
        
        var button = Ext.apply(new Ext.Button(this.actions_createAccounts), {
            scale: 'medium',
            rowspan: 2,
            iconAlign: 'top'
        });
        
        var additionalActions = [this.actions_exportIPAggregate];
        this.actionUpdater.addActions(additionalActions);
        return [button];
    },
    
    /**
     * Books remaining vacation from an old year to the new year
     * 
     * @param {} action
     * @param {} event
     */
    bookRemaining: function(action, event) {
        var selections = this.getGrid().getSelectionModel().getSelections();
        var ids = [];
        
        Ext.each(selections, function(sel) {
            ids.push(sel.getId());
        });
        
        var req = Ext.Ajax.request({
            url : 'index.php',
            timeout: 60000*5,
            params : { method : 'HumanResources.bookRemaining', ids: ids},
            success : function(_result, _request) {
                this.onAfterBookRemaining(Ext.decode(_result.responseText));
            },
            failure : function(exception) {
                Tine.HumanResources.handleRequestException(exception);
            },
            scope: this
        });
    },
    
    /**
     * is called if booking remaining was successfull
     * 
     * @param {Object} response
     */
    onAfterBookRemaining: function(response) {
        Ext.MessageBox.show({
            buttons: Ext.Msg.OK,
            icon: Ext.MessageBox.INFO,
            title: this.app.i18n._('Booking has been successfull!'), 
            msg: this.app.i18n._('The remaining vacation days of the selected accounts have been booked successfully!')
        });
    }
});
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * FreeTime grid panel
 * 
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.FreeTimeGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 * 
 * <p>FreeTime Grid Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>    
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.FreeTimeGridPanel
 */
Tine.HumanResources.FreeTimeGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    
    editDialogRecordProperty: null,
    editDialog: null,
    storeRemoteSort: false,
    defaultSortInfo: {field: 'firstday_date', direction: 'DESC'},
    /**
     * if a vacation record gets deleted, this is needed to calculate
     * the remaining vacation days in the freetime edit dialog (vacation)
     * 
     * @type array
     */
    removedVacationDays: null,
    removedSicknessDays: null,
    
    localSicknessDays: null,
    localVacationDays: null,
    /**
     * set type before to diff vacation/sickness
     * @type 
     */
    freetimeType: null,
    
    usePagingToolbar: false,
    
    /**
     * inits this cmp
     * 
     * @private
     */
    initComponent: function() {
        this.bbar = [];
        
        this.action_bookSicknessAsVacation = new Ext.Action({
            text: this.app.i18n._('Book as vacation'),
            hidden: true,
            handler: this.onBookSicknessAsVacation,
            scope: this,
            allowMultiple: false
        });
        
        this.contextMenuItems = [this.action_bookSicknessAsVacation];
        
        if (this.freetimeType) {
            if (this.freetimeType == 'SICKNESS') {
                this.setTitle(this.app.i18n._('Sickness'));
                this.i18nRecordName = this.app.i18n._('Sickness Days');
                this.i18nRecordsName = this.app.i18n._('Sickness Days');
            } else {
                this.setTitle(this.app.i18n._('Vacation'));
                this.i18nRecordName = this.app.i18n._('Vacation Days');
                this.i18nRecordsName = this.app.i18n._('Vacation Days');
            }
        }
        
        this.removedSicknessDays = {};
        this.removedVacationDays = {};
        this.localSicknessDays   = null;
        this.localVacationDays   = null;
        
        this.i18nEmptyText = this.i18nEmptyText || String.format(this.app.i18n._("There could not be found any {0}. Please try to change your filter-criteria or view-options."), this.i18nRecordsName);        
        
        Tine.HumanResources.FreeTimeGridPanel.superclass.initComponent.call(this);
        
        this.fillBottomToolbar();
    },
    
    /**
     * book sickness as vacation
     * 
     * @param {Ext.grid.GridPanel} grid
     * @param {Ext.EventObject} e
     */
    onBookSicknessAsVacation: function(grid, e) {
        var record = this.getGrid().getSelectionModel().getSelections()[0];

        // check if enough vacation days are available
        var request = Ext.Ajax.request({
            url : 'index.php',
            params : { 
                method : 'HumanResources.getFeastAndFreeDays',
                _employeeId: record.get('employee_id'),
                _year: parseInt(record.get('firstday_date').format('Y')), 
                _freeTimeId: null,
                _accountId: record.get('account_id') ? record.get('account_id').id : null
            },
            success : function(_result, _request) {
                var response = Ext.decode(_result.responseText);
                this.onBookSicknessAsVacationSuccess(response.results, record);
            },
            failure : function(exception) {
                Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
            },
            scope: this
        });
    },
    
    /**
     * callback if the request from onBookSicknessAsVacation doesn't fail
     * 
     * @param {Object} results
     * @param {Tine.HumanResources.Model.Freetime} record
     */
    onBookSicknessAsVacationSuccess: function(results, record) {
        // if there are not enough vacation days left
        if (results.remainingVacation < record.get('days_count')) {
            Ext.MessageBox.show({
                title: this.app.i18n._('Could not book as vacation'), 
                msg: this.app.i18n._('The unexcused sickness days could not be booked as vacation. There are not enough days left!'),
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.WARNING
            });
            return;
        } 
        
        this.store.remove(record);
        record.set('type', 'vacation');
        record.set('status', 'ACCEPTED');
        this.editDialog.vacationGridPanel.getStore().add(record);
        
        // set sickness of parent record (employee)
        var sickness = [];
        this.getGrid().getStore().each(function(item) {
            sickness.push(item.data);
        });
        this.editDialog.record.set('sickness', sickness);
        
        // set vacation of parent record (employee)
        var vacation = [];
        this.editDialog.vacationGridPanel.getStore().each(function(item) {
            vacation.push(item.data);
        });
        
        this.editDialog.record.set('vacation', vacation);
    },
    
    /**
     * returns rows context menu
     * 
     * @param {Ext.grid.GridPanel} grid
     * @param {Number} row
     * @param {Ext.EventObject} e
     */
    getContextMenu: function(grid, row, e) {
        var selModel = grid.getSelectionModel();
        this.action_bookSicknessAsVacation.setHidden(true);
        if (selModel.getSelections().length == 1) {
            if (selModel.getSelections()[0].data.status == 'UNEXCUSED') {
                this.action_bookSicknessAsVacation.setHidden(false);
            }
        }
        
        return Tine.HumanResources.FreeTimeGridPanel.superclass.getContextMenu.call(this, grid, row, e);
    },
    
    /**
     * will be called in Edit Dialog Mode
     */
    fillBottomToolbar: function() {
        var tbar = this.getBottomToolbar();
        tbar.addButton(new Ext.Button(this.action_editInNewWindow));
        tbar.addButton(new Ext.Button(this.action_addInNewWindow));
        tbar.addButton(new Ext.Button(this.action_deleteRecord));
    },
    
    /**
     * overwrites and calls superclass
     * 
     * @param {Object} button
     * @param {Tine.Tinebase.data.Record} record
     * @param {Array} plugins
     */
    onEditInNewWindow: function(button, record, plugins) {
        // the name 'button' should be changed as this can be called in other ways also
        button.fixedFields = {
            'employee_id': this.editDialog.record.data,
            'type':        this.freetimeType
        };
        
        // collect free days not saved already
        var localVacationDays = {}, localSicknessDays = {};
        
        this.editDialog.vacationGridPanel.store.each(function(record) {
                var accountId = Ext.isObject(record.get('account_id')) ? record.get('account_id').id : record.get('account_id');
                if (! localVacationDays.hasOwnProperty(accountId)) {
                    localVacationDays[accountId] = [];
                }
                localVacationDays[accountId] = localVacationDays[accountId].concat(record.data.freedays ? record.data.freedays : []);
        }, this);
        
        this.editDialog.sicknessGridPanel.store.each(function(record) {
                var accountId = Ext.isObject(record.get('account_id')) ? record.get('account_id').id : record.get('account_id');
                if (! localSicknessDays.hasOwnProperty(accountId)) {
                    localSicknessDays[accountId] = [];
                }
                localSicknessDays[accountId] = localSicknessDays[accountId].concat(record.data.freedays ? record.data.freedays : []);
        });
        
        var additionalConfig = {
            localVacationDays: localVacationDays,
            localSicknessDays: localSicknessDays,
            removedVacationDays: this.removedVacationDays,
            removedSicknessDays: this.removedSicknessDays
        };
        
        this.editDialogClass = (this.freetimeType == 'SICKNESS') ? Tine.HumanResources.SicknessEditDialog : Tine.HumanResources.VacationEditDialog;
        
        Tine.HumanResources.FreeTimeGridPanel.superclass.onEditInNewWindow.call(this, button, record, plugins, additionalConfig);
    },
    /**
     * overwrites the default function, no refactoring needed, this file will be deleted in the next release
     */
    initFilterPanel: function() {},
    
    /**
     * renders the different status keyfields
     * @param {String} value
     * @param {Object} b
     * @param {Tine.HumanResources.Model.FreeTime} record
     */
    renderStatus: function(value, row, record) {
        if (record.get('type') == 'sickness') {
            if (! this.sicknessStatusRenderer) {
                this.sicknessStatusRenderer = Tine.Tinebase.widgets.keyfield.Renderer.get('HumanResources', 'sicknessStatus');
            }
            return this.sicknessStatusRenderer(value, row, record);
        } else {
            if (! this.vacationStatusRenderer) {
                this.vacationStatusRenderer = Tine.Tinebase.widgets.keyfield.Renderer.get('HumanResources', 'vacationStatus');
            }
            return this.vacationStatusRenderer(value, row, record);
        }
    },
    /**
     * renders the type
     * @param {String} value
     * @param {Object} b
     * @param {Tine.HumanResources.Model.FreeTime} record
     */
    renderType: function(value, row, record) {
        if (! this.app) {
            this.app = Tine.Tinebase.appMgr.get('HumanResources');
        }
        
        if (record.get('type') == 'sickness') {
            return this.app.i18n._('Sickness');
        } else {
            return this.app.i18n._('Vacation');
        }
    },
    
    /**
     * delete records
     * 
     * @param {SelectionModel} sm
     * @param {Array} records
     */
    deleteRecords: function(sm, records) {
        
        if (! this.removedVacationDays) {
            this.removedVacationDays = {};
        }
        
        // collect freetimes deleted locally but not persisted already
        Ext.each(records, function(record) {
            
            if (record.get('id').length > 13) {
            
                var accountId = Ext.isObject(record.get('account_id')) ? record.get('account_id').id : record.get('account_id');
                
                if (record.get('type') == 'vacation') {
                    if (! this.removedVacationDays.hasOwnProperty(accountId)) {
                        this.removedVacationDays[accountId] = [];
                    }
                    this.removedVacationDays[accountId] = this.removedVacationDays[accountId].concat(record.get('freedays'));
                } else {
                    if (! this.removedSicknessDays.hasOwnProperty(accountId)) {
                        this.removedSicknessDays[accountId] = [];
                    }
                    this.removedSicknessDays[accountId] = this.removedSicknessDays[accountId].concat(record.get('freedays'));
                }
            }
        }, this);
        
        Tine.HumanResources.FreeTimeGridPanel.superclass.deleteRecords.call(this, sm, records);
    },
    
    /**
     * called when the store gets updated, e.g. from editgrid
     * 
     * @param {Ext.data.store} store
     * @param {Tine.Tinebase.data.Record} record
     * @param {String} operation
     */
    onStoreUpdate: function(store, record, operation) {
        if (Ext.isObject(record.get('employee_id'))) {
            record.set('employee_id', record.get('employee_id').id)
        }
        
        Tine.HumanResources.FreeTimeGridPanel.superclass.onStoreUpdate.call(this, store, record, operation);
    }
});

Tine.widgets.grid.RendererManager.register('HumanResources', 'FreeTime', 'status', Tine.HumanResources.FreeTimeGridPanel.prototype.renderStatus);
Tine.widgets.grid.RendererManager.register('HumanResources', 'FreeTime', 'type', Tine.HumanResources.FreeTimeGridPanel.prototype.renderType);
/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.ExtraFreeTimeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>ExtraFreeTime Compose Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * Create a new Tine.HumanResources.ExtraFreeTimeEditDialog
 */
Tine.HumanResources.ExtraFreeTimeEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    windowNamePrefix: 'ExtraFreeTimeEditWindow_',
    appName: 'HumanResources',
    recordClass: Tine.HumanResources.Model.ExtraFreeTime,
    recordProxy: Tine.HumanResources.freetimeBackend,
    evalGrants: false,
    showContainerSelector: false,
    mode: 'local',
    windowWidth: 400,
    windowHeight: 350,
    /**
     * show private Information (autoset due to rights)
     * @type 
     */
    showPrivateInformation: null,
    
    /**
     * overwrite update toolbars function (we don't have record grants yet)
     * @private
     */
    updateToolbars: Ext.emptyFn,
    
    /**
     * inits the component
     */
    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('HumanResources')
        Tine.HumanResources.ExtraFreeTimeEditDialog.superclass.initComponent.call(this);
    },
    
    /**
     * executed after record got updated from proxy
     * 
     * @private
     */
    onRecordLoad: function() {
        // interrupt process flow until dialog is rendered
        if (! this.rendered) {
            this.onRecordLoad.defer(250, this);
            return;
        }
        
        if (Ext.isString(this.record)) {
            this.record = this.recordProxy.recordReader({responseText: this.record});
        }
        
        Tine.HumanResources.ExtraFreeTimeEditDialog.superclass.onRecordLoad.call(this);
    },
    
    /**
     * returns dialog
     * 
     * NOTE: when this method gets called, all initalisation is done.
     * 
     * @return {Object}
     * @private
     */
    getFormItems: function() {
        return {
            xtype: 'tabpanel',
            border: false,
            plain:true,
            plugins: [{
                ptype : 'ux.tabpanelkeyplugin'
            }],
            defaults: {
                hideMode: 'offsets'
            },
            activeTab: 0,
            border: false,
            items:[{
                title: this.app.i18n._('Extra free time'),
                autoScroll: true,
                border: false,
                frame: true,
                layout: 'border',
                items: [{
                    region: 'center',
                    layout: 'hfit',
                    border: false,
                    items: [{
                        xtype: 'fieldset',
                        autoHeight: true,
                        title: this.app.i18n._('Extra free time'),
                        items: [{
                            xtype: 'columnform',
                            labelAlign: 'top',
                            formDefaults: {
                                xtype:'numberfield',
                                anchor: '100%',
                                labelSeparator: '',
                                allowBlank: false,
                                columnWidth: 1
                            },
                            items: [[{
                                    name: 'days', 
                                    fieldLabel: this.app.i18n._('Days')
                                }], [{
                                    xtype: 'widget-keyfieldcombo',
                                    app: 'HumanResources',
                                    keyFieldName: 'extraFreetimeType',
                                    fieldLabel: this.app.i18n._('Type'),
                                    name: 'type',
                                    showIcon: false
                                }], [{
                                    fieldLabel: this.app.i18n._('Expiration date'),
                                    xtype: 'datefield',
                                    name: 'expires'
                                }]
                            ]
                        }]
                    }]
                }, 
                {
                // activities and tags
                layout: 'accordion',
                animate: true,
                region: 'east',
                width: 210,
                split: true,
                collapsible: true,
                collapseMode: 'mini',
                header: false,
                margins: '0 5 0 5',
                border: true,
                items: [
                    new Ext.Panel({
                        title: this.app.i18n._('Description'),
                        iconCls: 'descriptionIcon',
                        layout: 'form',
                        labelAlign: 'top',
                        border: false,
                        items: [{
                            style: 'margin-top: -4px; border 0px;',
                            labelSeparator: '',
                            xtype: 'textarea',
                            name: 'description',
                            hideLabel: true,
                            grow: false,
                            preventScrollbars: false,
                            anchor: '100% 100%',
                            emptyText: this.app.i18n._('Enter description'),
                            requiredGrant: 'editGrant'
                        }]
                    }),
                    new Tine.widgets.tags.TagPanel({
                        app: 'HumanResources',
                        border: false,
                        bodyStyle: 'border:1px solid #B5B8C8;'
                    })
                ]
            }
                
                ]
            }, 
            new Tine.widgets.activities.ActivitiesTabPanel({
                app: this.appName,
                record_id: this.record.id,
                record_model: this.appName + '_Model_' + this.recordClass.getMeta('modelName')
                }) 
            ]
        };
    },
    
    /**
     * updates the statusbox wrap
     * 
     * @param {Tine.Tinebase.widgets.keyfield.ComboBox} the calling combo
     * @param {Tine.Tinebase.data.Record} the selected record
     * @param {Integer} the index of the selected value of the typecombo store
     */
    updateStatusBox: function(typeCombo, keyfieldRecord, index) {
        this.statusBoxWrap.layout.setActiveItem(index);
    },
    
    /**
     * initializes the status box
     */
    initStatusBox: function() {
        var isSickness = this.fixedFields.get('type') == 'SICKNESS';
        this.updateStatusBox(null, null, isSickness ? 0 : 1);
        var fieldName = isSickness ? 'sicknessStatus' : 'vacationStatus';
        this.getForm().findField(fieldName).setValue(this.record.get('status'));
    }
});/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2013-2014 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * ExtraFreeTime grid panel
 * 
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.ExtraFreeTimeGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 * 
 * <p>ExtraFreeTime Grid Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.HumanResources.ExtraFreeTimeGridPanel
 */
Tine.HumanResources.ExtraFreeTimeGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    /* local */
    storeRemoteSort: false,
    usePagingToolbar: false,
    
    /**
     * inits this cmp
     * 
     * @private
     */
    initComponent: function() {
        this.bbar = [];
        
        Tine.HumanResources.ExtraFreeTimeGridPanel.superclass.initComponent.call(this);
        this.fillBottomToolbar();
    },
    
    /**
     * will be called in Edit Dialog Mode
     */
    fillBottomToolbar: function() {
        var tbar = this.getBottomToolbar();
        tbar.addButton(new Ext.Button(this.action_editInNewWindow));
        tbar.addButton(new Ext.Button(this.action_addInNewWindow));
        tbar.addButton(new Ext.Button(this.action_deleteRecord));
    },

    /**
     * overwrites and calls superclass
     * 
     * @param {Object} button
     * @param {Tine.Tinebase.data.Record} record
     * @param {Array} addRelations
     */
    onEditInNewWindow: function(button, record, plugins) {
        // the name 'button' should be changed as this can be called in other ways also
        button.fixedFields = {
            'account_id':  this.editDialog.record.data
        };
        Tine.HumanResources.ExtraFreeTimeGridPanel.superclass.onEditInNewWindow.call(this, button, record, plugins);
    },

    /**
     * called when the store gets updated, e.g. from editgrid
     * 
     * @param {Ext.data.store} store
     * @param {Tine.Tinebase.data.Record} record
     * @param {String} operation
     */
    onStoreUpdate: function(store, record, operation) {
        if (Ext.isObject(record.get('account_id'))) {
            record.set('account_id', record.get('account_id').id)
        }
        Tine.HumanResources.ExtraFreeTimeGridPanel.superclass.onStoreUpdate.call(this, store, record, operation);
    }
});

Tine.widgets.grid.RendererManager.register('HumanResources', 'ExtraFreeTime', 'status', Tine.HumanResources.ExtraFreeTimeGridPanel.prototype.renderStatus);/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.AccountEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Account Edit Dialog</p>
 * <p></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * Create a new Tine.HumanResources.AccountEditDialog
 */
Tine.HumanResources.AccountEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /*
     * @private
     */
    evalGrants: false,

    windowWidth: 550,
    windowHeight: 560,
    
    /**
     * inits the component
     */
    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('HumanResources')
        Tine.HumanResources.AccountEditDialog.superclass.initComponent.call(this);
    },
    
    /**
     * executed after record got updated from proxy
     * 
     * @private
     */
    onRecordLoad: function() {
        // interrupt process flow until dialog is rendered
        if (! this.rendered) {
            this.onRecordLoad.defer(250, this);
            return;
        }
        Tine.HumanResources.AccountEditDialog.superclass.onRecordLoad.call(this);
        this.window.setTitle(String.format(this.app.i18n._('Edit {0} for {1} - {2}'), this.i18nRecordName, Ext.util.Format.htmlEncode(this.record.get('employee_id').n_fn), this.record.get('year')));
    },

    /**
     * returns dialog
     * 
     * NOTE: when this method gets called, all initalisation is done.
     * 
     * @return {Object}
     * @private
     */
    getFormItems: function() {
        
        this.extraFreeTimeGridPanel = new Tine.HumanResources.ExtraFreeTimeGridPanel({
            app: this.app,
            editDialog: this,
            editDialogRecordProperty: 'extra_free_times',
            disabled: false,
            frame: false,
            border: true,
            autoScroll: true,
            layout: 'border',
            title: this.app.i18n._('Extra free time')
        });
        // columnForm defaults
        var cfDefaults = {xtype: 'textfield', readOnly: true, columnWidth: .5, anchor: '100%'};
        return {
            xtype: 'tabpanel',
            border: false,
            plain:true,
            plugins: [{
                ptype : 'ux.tabpanelkeyplugin'
            }],
            defaults: {
                hideMode: 'offsets'
            },
            activeTab: 0,
            border: false,
            items: [{
                title: this.app.i18n._('Summary'),
                autoScroll: true,
                border: false,
                frame: true,
                layout: 'border',
                items: [{
                    region: 'center',
                    layout: 'hfit',
                    border: false,
                    items: [{
                        xtype: 'fieldset',
                        layout: 'hfit',
                        autoHeight: true,
                        title: this.app.i18n._('Free Times'),
                        items: [{
                            xtype: 'columnform',
                            formDefaults: cfDefaults,
                            labelAlign: 'top',
                            items: [[
                                {fieldLabel: this.app.i18n._('Possible vaction days'), name: 'possible_vacation_days', columnWidth: 1/5 },
                                {fieldLabel: this.app.i18n._('Remaining vaction days'), name: 'remaining_vacation_days', columnWidth: 1/5 },
                                {fieldLabel: this.app.i18n._('Taken vaction days'), name: 'taken_vacation_days', columnWidth: 1/5 },
                                {fieldLabel: this.app.i18n._('Expired vaction days'), name: 'expired_vacation_days', columnWidth: 1/5 },
                                {fieldLabel: this.app.i18n._('Rebooked vaction days'), name: 'rebooked_vacation_days', columnWidth: 1/5 }
                            ]]
                        }]
                    }, {
                        xtype: 'fieldset',
                        layout: 'hfit',
                        autoHeight: true,
                        title: this.app.i18n._('Sickness'),
                        items: [{
                            xtype: 'columnform',
                            formDefaults: cfDefaults,
                            labelAlign: 'top',
                            items: [[
                                {fieldLabel: this.app.i18n._('Excused sickness days'), name: 'excused_sickness' },
                                {fieldLabel: this.app.i18n._('Unexcused sickness days'), name: 'unexcused_sickness' }
                            ]]
                        }]
                    }, {
                        xtype: 'fieldset',
                        layout: 'hfit',
                        autoHeight: true,
                        title: this.app.i18n._('Working Time'),
                        items: [{
                            xtype: 'columnform',
                            formDefaults: cfDefaults,
                            labelAlign: 'top',
                            items: [[
                                {fieldLabel: this.app.i18n._('Days to work'), name: 'working_days' },
                                {fieldLabel: this.app.i18n._('Hours to work'), name: 'working_hours' }
                            ], [
                                {fieldLabel: this.app.i18n._('Days to work after vacation and sickness'), name: 'working_days_real' },
                                {fieldLabel: this.app.i18n._('Hours to work after vacation and sickness'), name: 'working_hours_real' }
                            ]]
                        }]
                    }, {
                        xtype: 'fieldset',
                        layout: 'hfit',
                        autoHeight: true,
                        title: this.app.i18n._('Miscellaneous'),
                        items: [{
                            xtype: 'columnform',
                            labelAlign: 'top',
                            items: [[{
                                xtype: 'textarea',
                                height: 180,
                                disabled: false,
                                readOnly: false,
                                fieldLabel: this.app.i18n._('Description'),
                                name: 'description', 
                                columnWidth: 1 
                            }]]
                        }]
                    }]
                }]},
                this.extraFreeTimeGridPanel,
                new Tine.widgets.activities.ActivitiesTabPanel({
                    app: this.appName,
                    record_id: this.record.id,
                    record_model: this.appName + '_Model_' + this.recordClass.getMeta('modelName')
                }) 
            ]
        };
    }
});/*
 * Tine 2.0
 * 
 * @package     HumanResources
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO make config saving work and activate update action again
 */

Ext.ns('Tine.HumanResources');

/**
 * @namespace   Tine.HumanResources
 * @class       Tine.HumanResources.AdminPanel
 * @extends     Ext.FormPanel
 * @author      Alexander Stintzing <alex@stintzing.net>
 */
Tine.HumanResources.AdminPanel = Ext.extend(Ext.FormPanel, {
    appName : 'HumanResources',

    layout : 'fit',
    border : false,
    cls : 'tw-editdialog',    

    labelAlign : 'top',

    anchor : '100% 100%',
    deferredRender : false,
    buttonAlign : null,
    bufferResize : 500,

    /**
     * init component
     */
    initComponent: function() {

        if (!this.app) {
            this.app = Tine.Tinebase.appMgr.get(this.appName);
        }

        Tine.log.debug('initComponent: appName: ', this.appName);
        Tine.log.debug('initComponent: app: ', this.app);

        // init actions
        this.initActions();
        // init buttons and tbar
        this.initButtons();

        // get items for this dialog
        this.items = this.getFormItems();
        
        this.loadRecord();
        
        Tine.HumanResources.AdminPanel.superclass.initComponent.call(this);
    },

    /**
     * init actions
     */
    initActions: function() {
        this.action_cancel = new Ext.Action({
            text : this.app.i18n._('Cancel'),
            minWidth : 70,
            scope : this,
            handler : this.onCancel,
            iconCls : 'action_cancel'
        });

        this.action_update = new Ext.Action({
            text : this.app.i18n._('OK'),
            minWidth : 70,
            scope : this,
            handler : this.onUpdate,
            iconCls : 'action_saveAndClose'
        });
    },

    /**
     * init buttons
     */
    initButtons : function() {
        this.fbar = [ '->', this.action_cancel , this.action_update ];
    },  

    /**
     * is called when the component is rendered
     * @param {} ct
     * @param {} position
     */
    onRender : function(ct, position) {
        Tine.HumanResources.AdminPanel.superclass.onRender.call(this, ct, position);

        // generalized keybord map for edit dlgs
        new Ext.KeyMap(this.el, [ {
            key : [ 10, 13 ], // ctrl + return
            ctrl : true,
            fn : this.onUpdate,
            scope : this
        } ]);

        this.loadMaskCt = ct;
    },
    
    /**
     * closes the window
     */
    onCancel: function() {
        this.fireEvent('cancel');
        this.purgeListeners();
        this.window.close();
    },

    /**
     * save record and close window
     */
    onUpdate : function() {
        
        // check date
        var date = this.getForm().findField('vacationExpires').getValue();
        dates = date.split(/-/);
        var date = new Date(2013, parseInt(dates[0])-1, dates[1]);
        
        if (!(parseInt(date.format('m')) == parseInt(dates[0]) && parseInt(date.format('d')) == parseInt(dates[1]))) {
            this.getForm().findField('vacationExpires').markInvalid(this.app.i18n._('Please use the following format: MM-DD'));
            return;
        }
        
        if (! this.loadMask) {
            this.loadMask = new Ext.LoadMask(this.loadMaskCt);
        }
        
        this.loadMask.msg = 'Saving...';
        this.loadMask.show();

        Ext.Ajax.request({
            url: 'index.php',
            scope: this,
            params: {
                method: 'HumanResources.setConfig',
                config: {
                    defaultFeastCalendar: this.getForm().findField('defaultFeastCalendar').getValue(),
                    vacationExpires: this.getForm().findField('vacationExpires').getValue()
                }
            },
            success : function(_result, _request) {
                this.loadMask.hide();
                // reload mainscreen to make sure registry gets updated
                Tine.Tinebase.common.reload();
            }
        });
    },

    loadRecord: function() {
        
        if (! this.rendered) {
            this.loadRecord.defer(100, this);
            return false;
        }
        
        this.loadMask = new Ext.LoadMask(this.loadMaskCt);
        this.loadMask.show();
        
        var config = Tine.HumanResources.registry.get('config');
        
        var calId = config.defaultFeastCalendar.value;
        if (calId) {
            var request = Ext.Ajax.request({
                url: 'index.php',
                scope: this,
                params: {
                    method: 'Admin.getContainer',
                    id: calId
                },
                success : function(_result, _request) {
                    this.onRecordLoad(Ext.decode(_result.responseText), config.vacationExpires.value);
                }
            });
        } else {
            this.onRecordLoad(null, config.vacationExpires.value);
        }
    },
    
    onRecordLoad: function(defaultFeastCalendar, vacationExpires) {
        this.getForm().findField('defaultFeastCalendar').setValue(defaultFeastCalendar);
        this.getForm().findField('vacationExpires').setValue(vacationExpires);
        
        this.loadMask.hide();
    },
    
    /**
     * create and return form items
     * @return Object
     */
    getFormItems: function() {
        var dfc = Tine.HumanResources.registry.get('config').defaultFeastCalendar;
        
        return {
            border: false,
            frame:  false,
            layout: 'border',

            items: [{
                region: 'center',
                border: false,
                frame:  false,
                layout : {
                    align: 'stretch',
                    type:  'vbox'
                    },
                items: [{
                    layout:  'form',
                    margins: '10px 10px',
                    border:  false,
                    frame:   false,
                    items: [
                        Tine.widgets.form.RecordPickerManager.get('Tinebase', 'Container', {
                            containerName: this.app.i18n._('Calendar'),
                            containersName: this.app.i18n._('Calendars'),
                            appName: 'Calendar',
                            requiredGrant: 'readGrant',
                            hideTrigger2: true,
                            allowBlank: false,
                            fieldLabel: this.app.i18n._(dfc.definition.label),
                            name: 'defaultFeastCalendar',
                            blurOnSelect: true
                        }),
                        new Ext.form.TextField({
                            fieldLabel: this.app.i18n._('Vacation expires'),
                            name: 'vacationExpires'
                        })
                    ] 
                }]
            }]
        };
    } 
});

Tine.HumanResources.AdminPanel.openWindow = function(config) {
    var window = Tine.WindowFactory.getWindow({
        modal: true,
        width : 240,
        height : 250,
        contentPanelConstructor : 'Tine.HumanResources.AdminPanel',
        contentPanelConstructorConfig : config
    });
    return window;
};