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

var FlowLayout;
/**
 * @name jls.gui.FlowLayout
 * @augments jls.gui.Layout
 * @class This class represents a flow layout. The children can have an absolute or a relative position,
 * these two layouts does not interfer, overlapping must be fix using z-index.
 * <p>Child style position: <b>absolute</b>.
 * The absolute position is defined using a combination of the following style options: left, right, top, bottom, width, height.
 * If some options are conflicting each other then the last ones are ignored,
 * the conflicting options and their priorities are: width, left, right and height, top, bottom.</p>
 * <p>Child style position: <b>relative</b>.
 * Children are positioned in a flow depending on the following style options:
 * direction (ltr, rtl), textAlign (left, right, center, justify), verticalAlign (top, middle, bottom).</p>
 */
FlowLayout = Class.create(Layout,
{
    onUpdate : function() {
    	/*
    	 * update relative children then absolute
    	 */
    	// TODO use several width: px, %, weight
        var cSize = this._element.getClientSize();
        var cWidth = cSize[0];
        var cHeight = cSize[1];
    	//jls.lang.System.out.println('update(): [' + cWidth + ', ' + cHeight + ']');
        var cStyle = this._element.getStyle();
        var hGap = cStyle.getPropertyValue('hGap') || 0;
        var vGap = cStyle.getPropertyValue('vGap') || 0;
        var lines = [];
        var lineWeight = 0;
        var lineHeight = 0;
        var lineWidth = 0;
        var lineElements = [];
        var globalHeight = 0;
        var globalWidth = 0;
        var childCount = this._element.getChildCount();
        // Special case for only one child without layout styles (left, top, width, height)
        if (childCount == 1) {
            var child = this._element.getChild(0);
            var style = child.getStyle();
            if ((style.getPropertyValue('width') == null) && (style.getPropertyValue('height') == null) &&
                (style.getPropertyValue('left') == null) && (style.getPropertyValue('top') == null))
            {
                FlowLayout.place(child, hGap, vGap, cWidth - hGap * 2, cHeight - vGap * 2);
                return;
            }
        }
        for (var i = 0; i < childCount; i++) {
            var child = this._element.getChild(i);
            var style = child.getStyle();
            var position = style.getPropertyValue('position');
            var rawWidth = style.getPropertyValue('width');
            var rawHeight = style.getPropertyValue('height');
            if (position == 'relative') {
                var weight = FlowLayout.getWeight(rawWidth);
                var width = weight > 0 ? 0 : FlowLayout.computeSize(rawWidth, cWidth);
                var height = FlowLayout.computeSize(rawHeight, cHeight, childCount);
            	/*
            	 * TODO Manage display:block styles
            	 */
                if ((style.getPropertyValue('clear') == 'left') ||
                    ((lineElements.length > 0) && (lineElements[lineElements.length - 1].element.getStyle().getPropertyValue('clear') == 'right')) ||
                    (lineWidth + (lineElements.length > 0 ? hGap : 0) + width > cWidth))
                {
                    globalHeight += vGap;
                	// new line
                	lines.push({
                		weight: lineWeight,
                		width: lineWidth,
                		height: lineHeight,
                		elements: lineElements
                	});
                	// compute global
                    if (lineWidth > globalWidth) {
                    	globalWidth = lineWidth;
                    }
                    globalHeight += lineHeight;
                	//jls.lang.System.out.println('lines[' + (lines.length - 1) + ']: ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
                    // reset
                    lineElements = [];
                    lineWeight = 0;
                	lineWidth = 0;
                    lineHeight = 0;
                }
                lineWidth += hGap;
                lineElements.push({
            		width: width,
            		height: height,
            		rawWidth: rawWidth,
            		rawHeight: rawHeight,
            		element: child
                });
                lineWeight += weight;
                lineWidth += width;
                if (height > lineHeight) {
                	lineHeight = height;
                }
            	//jls.lang.System.out.println('child[' + i + ']: ' + width + 'x' + height + ', ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
            } else if (position == 'absolute') {
                var width = FlowLayout.computeSize(rawWidth, cWidth);
                var height = FlowLayout.computeSize(rawHeight, cHeight);
                var x = 0;
                var y = 0;
                var w = 0;
                var h = 0;
                var left = FlowLayout.computeSize(style.getPropertyValue('left'), cWidth);
                var top = FlowLayout.computeSize(style.getPropertyValue('top'), cHeight);
                var right = FlowLayout.computeSize(style.getPropertyValue('right'), cWidth);
                var bottom = FlowLayout.computeSize(style.getPropertyValue('bottom'), cHeight);
                // compute horizontal
            	if (width != null) {
            		w = width;
            	} else if ((left != null) && (right != null)) {
            		w = cWidth - right - left;
            	} else {
            		w = 10; // TODO auto
            	}
            	if (left != null) {
            		x = left;
            	} else if (right != null) {
            		x = cWidth - right - w;
            	} else {
            		x = 0; // default
            	}
                // compute vertical
            	if (height != null) {
            		h = height;
            	} else if ((top != null) && (bottom != null)) {
            		h = cHeight - bottom - top;
            	} else {
            		h = 10; // TODO auto
            	}
            	if (top != null) {
            		y = top;
            	} else if (right != null) {
            		y = cHeight - bottom - h;
            	} else {
            		y = 0; // default
            	}
            	FlowLayout.place(child, x, y, w, h);
            } else {
            	throw new Exception('Invalid position: "' + position + '"');
            }
        }
        if (lineElements.length > 0) {
            if (lines.length > 0) {
                globalHeight += vGap;
            }
        	// new line
        	lines.push({
                weight: lineWeight,
                width: lineWidth,
        		height: lineHeight,
        		elements: lineElements
        	});
        	// compute global
            if (lineWidth > globalWidth) {
            	globalWidth = lineWidth;
            }
            globalHeight += lineHeight;
        	//jls.lang.System.out.println('lines[' + (lines.length - 1) + ']: ' + lineWidth + 'x' + lineHeight + ', ' + globalWidth + 'x' + globalHeight);
        }
    	//jls.lang.System.out.println('update(): ' + cWidth + 'x' + cHeight + ', ' + globalWidth + 'x' + globalHeight);
        var lineCount = lines.length;
        if (lineCount > 0) {
            var direction = cStyle.getPropertyValue('direction');
            var verticalPosition = cStyle.getPropertyValue('verticalPosition');
            var textAlign = cStyle.getPropertyValue('textAlign');
            var verticalAlign = cStyle.getPropertyValue('verticalAlign');
            var y = vGap;
            if (verticalPosition == 'middle') {
            	y = Math.floor((cHeight - globalHeight) / 2);
            } else if (verticalPosition == 'bottom') {
            	y = cHeight - globalHeight;
            }
            for (var i = 0; i < lineCount; i++) {
            	var line = lines[i];
                var x = hGap;
                var lineWidth = line.weight > 0 ? (cWidth - hGap * 2) : line.width;
                if (textAlign == 'center') {
                	x = Math.floor((cWidth - lineWidth) / 2);
                } else if (textAlign == 'right') {
                	x = cWidth - lineWidth;
                }
            	lineElements = line.elements;
                if (direction == 'rtl') {
                    for (var j = lineElements.length - 1; j >= 0; j--) {
                    	var e = lineElements[j];
                        var w;
                        var h = e.height;
                        if (line.weight > 0) {
                            w = FlowLayout.computeSize(e.rawWidth, lineWidth - line.width, line.weight);
                        } else {
                            w = e.width;
                        }
                    	FlowLayout.placeElement(verticalAlign, line.height, e.element, x, y, w, h);
                    	x += w + hGap;
                    }
                } else {
                    for (var j = 0; j < lineElements.length; j++) {
                    	var e = lineElements[j];
                        var w;
                        var h = e.height;
                        if ((line.weight > 0) && (e.width == 0)) {
                            w = FlowLayout.computeSize(e.rawWidth, lineWidth - line.width, line.weight);
                            //jls.lang.System.out.println('computeSize(' + e.rawWidth + ', ' + cWidth + ', ' + line.weight + ') => ' + w);
                        } else {
                            w = e.width;
                        }
                    	FlowLayout.placeElement(verticalAlign, line.height, e.element, x, y, w, h);
                    	x += w + hGap;
                    }
                }
                y += line.height + vGap;
            }
        }
    }
});

Object.extend(FlowLayout,
{
    isWeight : function(value) {
        return value.charAt(value.length - 1) == 'w';
    },
    getWeight : function(value) {
        if ((typeof value != 'string') || (value.length < 2)) {
            return 0;
        }
        value = value.match(/([0-9]+)(.*)/);
        return value[2] == 'w' ? parseInt(value[1]) : 0;
        /*var w = value[2] == 'w' ? parseInt(value[1]) : 0;
        jls.lang.System.out.println('getWeight(' + value + ') => ' + w);
        return w;*/
    },
    computeSize : function(value, size, totalWeight) {
        if (value == null) {
            return null;
        }
        if (typeof value == 'number') {
            return value;
        }
        if ((typeof value != 'string') || (value.length == 0)) {
            throw new Exception('Illegal type of value "' + (typeof value) + '"');
        }
        value = value.match(/([0-9]+)(.*)/);
        var numberValue = value[1];
        var typeValue = value[2] || 'px';
        switch (typeValue) {
        case 'px':
            return Math.round(numberValue);
        case '%':
            return Math.round(numberValue * size / 100);
        case 'w':
            if (typeof totalWeight == 'undefined') {
                throw new Exception('The total weight is missing');
            }
            //jls.lang.System.out.println('computeSize(' + value + ', ' + size + ', ' + totalWeight + ') => ' + Math.round(numberValue * size / totalWeight));
            return Math.round(numberValue * size / totalWeight);
        default:
            throw new Exception('Illegal size type "' + typeValue + '"');
        }
    },
    placeElement : function(verticalAlign, lineHeight, child, x, y, w, h) {
    	if (verticalAlign == 'middle') {
    		y = y + Math.floor((lineHeight - h) / 2);
    	} else if (verticalAlign == 'bottom') {
    		y = y + lineHeight - h;
    	}
    	FlowLayout.place(child, x, y, w, h);
    },
    place : function(child, x, y, w, h) {
        //jls.lang.System.out.println('[' + x + ', ' + y + ', ' + w + ', ' + h + ']');
        //child.setLocation([x, y]);
        child.setBounds([x, y, w, h]);
        child.update();
    }
});

return FlowLayout;
});
