/*
 * Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
 * Haulmont Technology proprietary and confidential.
 * Use is subject to license terms.

 * Author: Dmitry Abramov
 * Created: 03.02.2009 12:59:26
 * $Id$
 */
package com.haulmont.cuba.gui.xml.layout.loaders;

import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.GridLayout;
import com.haulmont.cuba.gui.components.QuasiComponent;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.gui.xml.layout.LayoutLoader;
import com.haulmont.cuba.gui.xml.layout.LayoutLoaderConfig;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.BooleanUtils;
import org.dom4j.Element;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.HashSet;

public class GridLayoutLoader extends ContainerLoader implements com.haulmont.cuba.gui.xml.layout.ComponentLoader {
    protected boolean[][] spanMatrix;

    public GridLayoutLoader(Context context, LayoutLoaderConfig config, ComponentsFactory factory) {
        super(context, config, factory);
    }

    public Component loadComponent(ComponentsFactory factory, Element element, Component parent) throws InstantiationException, IllegalAccessException {
        GridLayout component = factory.createComponent("grid");

        loadId(component, element);
        loadVisible(component, element);

        loadStyleName(component, element);

        final Element columnsElement = element.element("columns");
        final Element rowsElement = element.element("rows");

        int columnCount;
        final List<Element> columnElements = columnsElement.elements("column");
        if (columnElements.size() == 0) {
            columnCount = Integer.valueOf(columnsElement.attributeValue("count"));
            component.setColumns(columnCount);
            for (int i = 0; i < columnCount; i++) {
                component.setColumnExpandRatio(i, 1);
            }
        } else {
            columnCount = columnElements.size();
            component.setColumns(columnCount);
            int i = 0;
            for (Element columnElement : columnElements) {
                final String flex = columnElement.attributeValue("flex");
                if (!StringUtils.isEmpty(flex)) {
                    component.setColumnExpandRatio(i, Float.parseFloat(flex));
                }
                i++;
            }
        }

        final List<Element> rowElements = rowsElement.elements("row");
        final Set<Element> invisibleRows = new HashSet<Element>();

        int rowCount = 0;
        for (Element rowElement : rowElements) {
            String visible = rowElement.attributeValue("visible");
            if (visible == null) {
                final Element e = rowElement.element("visible");
                if (e != null) {
                    visible = e.getText();
                }
            }

            if (!StringUtils.isEmpty(visible)) {
                Boolean value = evaluateBoolean(visible);

                if (BooleanUtils.toBoolean(value)) {
                    rowCount++;
                } else {
                    invisibleRows.add(rowElement);
                }
            } else {
                rowCount++;
            }
        }

        component.setRows(rowCount);

        int j = 0;
        for (Element rowElement : rowElements) {
            final String flex = rowElement.attributeValue("flex");
            if (!StringUtils.isEmpty(flex)) {
                component.setRowExpandRatio(j, Float.parseFloat(flex));
            }
            j++;
        }

        spanMatrix = new boolean[columnCount][rowElements.size()];

        int row = 0;
        for (Element rowElement : rowElements) {
            if (!invisibleRows.contains(rowElement)) {
                loadSubComponents(component, rowElement, row);
                row++;
            }
        }

        loadSpacing(component, element);
        loadMargin(component, element);

        loadWidth(component, element);
        loadHeight(component, element);

        loadExpandable(component, element);

        loadAlign(component, element);

        assignFrame(component);

        return component;
    }

    protected void loadSubComponents(GridLayout component, Element element, int row) {
        final LayoutLoader loader = new LayoutLoader(context, factory, config);
        loader.setLocale(getLocale());
        loader.setMessagesPack(getMessagesPack());

        int col = 0;

        for (Element subElement : (Collection<Element>)element.elements()) {
            final Component subComponent = loader.loadComponent(subElement, component);

            String colspan = subElement.attributeValue("colspan");
            String rowspan = subElement.attributeValue("rowspan");

            while (spanMatrix[col][row]) {
                col++;
            }

            if (StringUtils.isEmpty(colspan) && StringUtils.isEmpty(rowspan)) {
                addSubComponent(component, subComponent, col, row, col, row);
            } else {
                int cspan = StringUtils.isEmpty(colspan) ? 0 : Integer.parseInt(colspan);
                int rspan = StringUtils.isEmpty(rowspan) ? 0 : Integer.parseInt(rowspan);

                fillSpanMatrix(col, row, cspan, rspan);
                addSubComponent(component, subComponent, col, row, col + cspan, row + rspan);
            }

            col++;
        }
    }

    private void addSubComponent(GridLayout grid, Component subComponent, int c1, int r1, int c2, int r2) {
        if (subComponent instanceof QuasiComponent) {
            Collection<Component> realComponents = ((QuasiComponent) subComponent).getRealComponents();
            if (realComponents.size() == 1) {
                Component comp = realComponents.iterator().next();
                grid.remove(comp);
                grid.add(comp, c1, r1, c2, r2);
            } else {
                throw new UnsupportedOperationException("Invalid nested components count");
            }
        } else {
            grid.add(subComponent, c1, r1, c2, r2);
        }
    }

    private void fillSpanMatrix(int col, int row, int cspan, int rspan) {
        for (int i = col; i < (col + cspan); i++) {
            for (int j = row; j < (row + rspan); j++) {
                if (spanMatrix[i][j]) throw new IllegalStateException();
                spanMatrix[i][j] = true;
            }
        }
    }

}

@@ -387,24 +387,72 @@
 ridLayout;%0D%0A
+import com.haulmont.cuba.gui.components.Label;%0D%0A
 import com.h
@@ -4516,16 +4516,70 @@
 int row)
+ throws InstantiationException, IllegalAccessException
  %7B%0D%0A    
@@ -5845,16 +5845,70 @@
  int r2)
+ throws IllegalAccessException, InstantiationException
  %7B%0D%0A    
@@ -6277,32 +6277,149 @@
       %7D else %7B%0D%0A
+                Label label = factory.createComponent(%22label%22);%0D%0A                grid.add(label, c1, r1, c2, r2);%0D%0A//
                 

add label if accessControl disabled all comp in row