﻿/*
 * Ext Scheduler v2.0 beta
 * Copyright(c) 2009-2010 Mats Bryntse Consulting
 * mats@ext-scheduler.com
 * http://www.ext-scheduler.com/license.html
 *
 */

Ext.ns('Sch.plugins');
 
/**
 * @ignore
 * @class Sch.plugins.Resize
 * @extends Ext.util.Observable
 * Plugin enabling resizing of event items
 * @constructor
 * @param {Object} config The object containing the configuration of this model.
 */
Sch.plugins.Resize = function(config) {
    Ext.apply(this, config);
    Sch.plugins.Resize.superclass.constructor.call(this);
};
 
Ext.extend(Sch.plugins.Resize, Ext.util.Observable, {
     /**
      * @cfg useTooltip {Boolean} false to not show a tooltip while resizing
      */
    useTooltip : true,
    
    /**
     * An empty function by default, but provided so that you can perform custom validation on 
     * the item being resized.
     * @param {Ext.data.Record} resourceRecord the resource of the row in which the event is located
     * @param {Ext.data.Record} eventRecord the event being resized
     * @param {Date} startDate
     * @param {Date} endDate
     * @param {Event} e The event object
     * @return {Boolean} isValid True if the creation event is valid, else false to cancel
     */
    validatorFn : function(resourceRecord, eventRecord, startDate, endDate, e) {
        return true;
    },
    
    /**
     * @cfg {Object} validatorFnScope
     * The scope for the validatorFn
     */
    validatorFnScope : null,
    
    init:function(grid) {
        this.grid = grid;
        
        if (!this.tipTemplate) {
            this.tipTemplate = new Ext.Template(
                '<div class="sch-timetipwrap {cls}">',
                    '<div class="sch-clock">',
                        '<img src="' + Ext.BLANK_IMAGE_URL + '" class="sch-hourIndicator" style="-moz-transform: rotate({startHourDegrees}deg);-webkit-transform: rotate({startHourDegrees}deg)"/>',
                        '<img src="' + Ext.BLANK_IMAGE_URL + '" class="sch-minuteIndicator" style="-moz-transform: rotate({startMinuteDegrees}deg);-webkit-transform: rotate({startMinuteDegrees}deg)"/>',
                        '{startText}',
                    '</div>',
                     '<div class="sch-clock">',
                        '<img src="' + Ext.BLANK_IMAGE_URL + '" class="sch-hourIndicator" style="-moz-transform: rotate({endHourDegrees}deg);-webkit-transform: rotate({endHourDegrees}deg)"/>',
                        '<img src="' + Ext.BLANK_IMAGE_URL + '" class="sch-minuteIndicator" style="-moz-transform: rotate({endMinuteDegrees}deg);-webkit-transform: rotate({endMinuteDegrees}deg)"/>',
                        '{endText}',
                    '</div>',
                '</div>'
            ).compile();
        }
        
        this.grid.on('render', this.onGridRender, this);
    },
    
    // private
    onGridRender : function() {
        this.grid.mon(this.grid.getView().mainBody, 'mousedown', function(e) {
            var domEl = e.getTarget('.sch-event'),
                rec = this.grid.getEventRecordFromDomId(domEl.id);
            if (this.grid.fireEvent('beforeresize', this.grid, rec, e) === false) {
                return;
            }
            e.stopEvent();
            this.createResizable(Ext.get(domEl), rec, e);
            this.grid.fireEvent('resizestart', this.grid, rec);
        }, 
        this,
        {
            delegate : '.x-resizable-handle'
        });
    },
    
    // private
    createResizable : function (el, eventRecord, e) {
       
        var t = e.getTarget(),
            isWest = !!t.className.match('x-resizable-handle-west'),
            origWidth = el.getWidth(),
            origLeft = el.getLeft(),
            resourceRecord = this.grid.getResourceRecordByElement(t),
            row = el.up('tr'),
            r = new Sch.LazyResizable(el, {
                row : row,
                adjustments : [-20, -20],
                resourceRecord : resourceRecord,
                eventRecord : eventRecord,
                handles: isWest ? 'w' : 'e',
                dynamic: true,
                widthIncrement : 1,
                width : origWidth,
                constrainTo : row, // Constrain the resize within the current TR node
                minWidth: 1,
                origLeft : origLeft,
                origWidth : origWidth,
                listeners : {
                    partialresize : { fn : this[isWest ? 'partialWestResize' : 'partialEastResize'], scope : this },
                    resize        : { fn : this.afterResize, scope : this }
                }
            },
            isWest ? 'west' : 'east',
            e
        );
        
        if (this.useTooltip) {
            if(!this.tip) {
                this.tip = new Ext.QuickTip({
                    cls : 'sch-tip',
                    width : 145,
                    height:40,
                    autoHide : false,
                    target : r.el,
                    anchor : 'b',
                    html : this.getTipContent(eventRecord.get('StartDate'), eventRecord.get('EndDate'), true)
                });
            }
            
            // HACK writing to non public member anchorTarget
            this.tip.anchorTarget = r.el;
            
            this.tip.show();
        }
    },
    
    // private
    partialEastResize : function (r, newWidth, oldWidth, e) {
        var g = this.grid,
            start = r.eventRecord.get('StartDate'),
            elRight = r.el.getRight(),
            colIndex = this.findColIndex(r.row, elRight),
            end = g.getTimeFromX(colIndex, elRight);
        
        if (colIndex < 0 || !start || !end) return;
        
        var roundedEnd = g.roundDate(end),
            valid = this.validatorFn.call(this.validatorFnScope || this, r.resourceRecord, r.eventRecord, start, roundedEnd) !== false;
        
        r.end = roundedEnd;
        
        g.fireEvent('partialresize', g, r.eventRecord, start, roundedEnd, r.el, e);
        
        if (this.useTooltip) {
            this.tip.body.update(this.getTipContent(start, end, valid));
        }
    },
    
    partialWestResize : function (r, newWidth, oldWidth, e) {
        var g = this.grid,
            end = r.eventRecord.get('EndDate'),
            elLeft = r.el.getLeft(),
            colIndex = this.findColIndex(r.row, elLeft);
        
        if (colIndex < 0) return;
        
        var start = g.getTimeFromX(colIndex, elLeft),
            roundedStart = g.roundDate(start);
        
        if (!start || !end) return;
        
        var valid = this.validatorFn.call(this.validatorFnScope || this, r.resourceRecord, r.eventRecord, roundedStart, end) !== false;
        r.start = roundedStart;
        
        g.fireEvent('partialresize', g, r.eventRecord, roundedStart, end, r.el, e);
        
        if (this.useTooltip) {
            this.tip.body.update(this.getTipContent(start, end, valid));
        }
    },
    
    // private
    findColIndex : function(row, x) {
         var firstTimeCell = row.down('td.sch-timetd'),
             firstTimeCellLeft = firstTimeCell.getLeft(),
             relativeX = x - firstTimeCellLeft,
             colIndex = Math.floor(relativeX / firstTimeCell.getWidth());
        return colIndex;
    },
    
    
    // private
    afterResize : function (r, w, h, e) {
        if (this.useTooltip) {
            this.tip.hide();
        }
        var resourceRecord = r.resourceRecord,
            eventRecord = r.eventRecord,
            oldStart = eventRecord.get('StartDate'),
            oldEnd = eventRecord.get('EndDate'),
            start = r.start || oldStart,
            end = r.end || oldEnd;
        
        if (start && end && (end - start > 0) && // Input sanity check
            ((start - oldStart !== 0) || (end - oldEnd !== 0)) && // Make sure start OR end changed
            this.validatorFn.call(this.validatorFnScope || this, resourceRecord, eventRecord, start, end, e) !== false) {
            
            eventRecord.beginEdit();
            eventRecord.set('StartDate', start);
            eventRecord.set('EndDate', end);
            eventRecord.endEdit();
        } else {
            this.grid.getView().refreshRow(resourceRecord);
        }
        
        // Destroy resizable 
        r.destroy();
        
        this.grid.fireEvent('afterresize', this.grid, eventRecord);
    },
    
    // private
    getTipContent : function(start, end, valid) {
        var g = this.grid,
            roundedStart = g.floorDate(start),
            roundedEnd = g.roundDate(end),
            formattedStart = g.getFormattedDate(start, 'floor'),
            formattedEnd = g.getFormattedEndDate(roundedEnd);
        
        return this.tipTemplate.apply({
            cls : valid ? 'sch-tip-ok' : 'sch-tip-notok',
            startText : formattedStart,
            endText : formattedEnd,
            startHourDegrees : roundedStart.getHours() * 30, 
            startMinuteDegrees : roundedStart.getMinutes() * 6,
            endHourDegrees : roundedEnd.getHours() * 30, 
            endMinuteDegrees : roundedEnd.getMinutes() * 6
        });
    }
}); 
