define('jls/gui/BorderLayout', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/Logger',
  'jls/gui/FlowLayout'
], function (
  Class,
  Exception,
  Logger,
  FlowLayout
) {

var BorderLayout;
/**
 * @name jls.gui.BorderLayout
 * @augments jls.gui.Layout
 * @class This class represents a border layout.
 * Child must define: region, splitter
 */
BorderLayout = Class.create(FlowLayout,
{
    initialize : function($super, element) {
        $super(element);
        this._regions = {};
    	this._splitSize = 0;
        this._borderLeft = 0;
        this._borderRight = 0;
        this._borderTop = 0;
        this._borderBottom = 0;
        this._isResizing = false;
        this._onMouseMove = this.onMouseMove.bind(this);
        this._onMouseOut = this.stopResize.bind(this);
        this._mouseOrigin = 0;
        this._borderOrigin = 0;
        this._resizingRegion = null;
    },
    startResize : function(event) {
    	if ((this._isResizing) || (this._splitSize == 0)) {
    		return;
    	}
        var cSize = this.getElement().getClientSize();
        var cWidth = cSize[0];
        var cHeight = cSize[1];
    	//jls.logger.trace('BorderLayout startResize: ' + cWidth + 'x' + cHeight + ' ' + this._borderLeft + '-' + this._borderRight + ', ' + this._borderTop + '-' + this._borderBottom);

    	if (this.isRegionSplit('top') && (event.clientY >= this._borderTop) && (event.clientY <= this._borderTop + this._splitSize)) {
    		this._resizingRegion = 'top';
            this._borderOrigin = this._borderTop;
    		this._mouseOrigin = event.clientY;
    	} else if (this.isRegionSplit('bottom') && (event.clientY >= cHeight - this._borderBottom - this._splitSize) && (event.clientY <= cHeight - this._borderBottom)) {
    		this._resizingRegion = 'bottom';
            this._borderOrigin = this._borderBottom;
    		this._mouseOrigin = event.clientY;
    	} else if (this.isRegionSplit('left') && (event.clientX >= this._borderLeft) && (event.clientX <= this._borderLeft + this._splitSize)) {
    		this._resizingRegion = 'left';
            this._borderOrigin = this._borderLeft;
    		this._mouseOrigin = event.clientX;
    	} else if (this.isRegionSplit('right') && (event.clientX >= cWidth - this._borderRight - this._splitSize) && (event.clientX <= cWidth - this._borderRight)) {
    		this._resizingRegion = 'right';
            this._borderOrigin = this._borderRight;
    		this._mouseOrigin = event.clientX;
    	} else {
    		return;
    	}
    	this._isResizing = true;
    	this.getElement().observe('mousemove', this._onMouseMove);
        this.getElement().observe('mouseout', this._onMouseOut);
    },
    onMouseMove : function(event) {
    	Logger.getInstance().trace('BorderLayout mousemove: ' + event.clientX + 'x' + event.clientY + ', region: ' + this._resizingRegion);
    	switch (this._resizingRegion) {
    	case 'top':
    		this._regions[this._resizingRegion].getStyle().setProperty('height', this._borderOrigin + event.clientY - this._mouseOrigin);
    		break;
    	case 'bottom':
    		this._regions[this._resizingRegion].getStyle().setProperty('height', this._borderOrigin + this._mouseOrigin - event.clientY);
    		break;
    	case 'left':
    		this._regions[this._resizingRegion].getStyle().setProperty('width', this._borderOrigin + event.clientX - this._mouseOrigin);
    		break;
    	case 'right':
    		this._regions[this._resizingRegion].getStyle().setProperty('width', this._borderOrigin + this._mouseOrigin - event.clientX);
    		break;
    	default:
    		return;
    	}
    	this.updateRegionStyle();
    	this.getElement().update();
    },
    stopResize : function(event) {
    	//jls.logger.trace('BorderLayout stopResize()');
    	if (this._isResizing) {
        	this.getElement().unobserve('mousemove', this._onMouseMove);
            this.getElement().unobserve('mouseout', this._onMouseOut);
            this._isResizing = false;
    	}
    },
    onCreate : function() {
        this.getElement().observe('mousedown', function(event) {
        	//jls.logger.trace('BorderLayout mousedown: ' + event.clientX + 'x' + event.clientY);
        	event.target.getLayout().startResize(event);
        });
        this.getElement().observe('mouseup', function(event) {
        	//jls.logger.trace('BorderLayout mouseup: ' + event.clientX + 'x' + event.clientY);
        	event.target.getLayout().stopResize(event);
        });
    },
    isRegionSplit : function(region) {
    	return (region in this._regions) && (this._regions[region].getStyle().getPropertyValue('splitter') == 'true');
    },
    getRegionStylePropertyValue : function(region, key, defaultValue) {
        if (region in this._regions) {
        	var value = this._regions[region].getStyle().getPropertyValue(key);
            if (value != null) {
            	return value;
            }
        }
        return defaultValue || 0;
    },
    updateRegionStyle : function() {
    	this._splitSize = this.getElement().getStyle().getPropertyValue('splitSize') || 0;
      	this._borderLeft = this.getRegionStylePropertyValue('left', 'width', 0);
      	this._borderRight = this.getRegionStylePropertyValue('right', 'width', 0);
      	this._borderTop = this.getRegionStylePropertyValue('top', 'height', 0);
      	this._borderBottom = this.getRegionStylePropertyValue('bottom', 'height', 0);
        for (var r in this._regions) {
	    	switch (r) {
	    	case 'center':
	    		this._regions[r].getStyle().setProperties({
	    			width: null,
	    			height: null,
	    			left: this._borderLeft + ('left' in this._regions ? this._splitSize : 0),
	    			right: this._borderRight + ('right' in this._regions ? this._splitSize : 0),
	    			top: this._borderTop + ('top' in this._regions ? this._splitSize : 0),
	    			bottom: this._borderBottom + ('bottom' in this._regions ? this._splitSize : 0),
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'top':
	    		this._regions[r].getStyle().setProperties({
	    			width: null,
	    			height: this._borderTop,
	    			left: 0,
	    			right: 0,
	    			top: 0,
	    			bottom: null,
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'bottom':
	    		this._regions[r].getStyle().setProperties({
	    			width: null,
	    			height: this._borderBottom,
	    			left: 0,
	    			right: 0,
	    			top: null,
	    			bottom: 0,
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'left':
	    		this._regions[r].getStyle().setProperties({
	    			width: this._borderLeft,
	    			height: null,
	    			left: 0,
	    			right: null,
	    			top: this._borderTop + ('top' in this._regions ? this._splitSize : 0),
	    			bottom: this._borderBottom + ('bottom' in this._regions ? this._splitSize : 0),
	    			position: 'absolute'
	    		});
	    		break;
	    	case 'right':
	    		this._regions[r].getStyle().setProperties({
	    			width: this._borderRight,
	    			height: null,
	    			left: null,
	    			right: 0,
	    			top: this._borderTop + ('top' in this._regions ? this._splitSize : 0),
	    			bottom: this._borderBottom + ('bottom' in this._regions ? this._splitSize : 0),
	    			position: 'absolute'
	    		});
	    		break;
	    	}
    	}
    },
    onAddChild : function($super, child) {
    	var region = child.getStyle().getPropertyValue('region');
    	// check region
    	if (region == null) {
    		throw new Exception('The region is not defined');
    	}
    	if (region in this._regions) {
    		throw new Exception('The region "' + region + '" is duplicated');
    	}
    	this._regions[region] = child;
    	this.updateRegionStyle();
        $super(child);
    },
    onRemoveChild : function(child) {
    	var region = child.getStyle().getPropertyValue('region');
    	if (region != null) {
        	delete this._regions[region];
        	this.updateRegionStyle();
    	}
        $super(child);
    }
});

return BorderLayout;
});
