/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.haulmont.cuba.desktop.sys.layout;

import com.haulmont.cuba.gui.components.SizeUnit;
import net.miginfocom.layout.AC;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.LC;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;
import java.awt.*;

public class MigBoxLayoutAdapter extends BoxLayoutAdapter {

    protected MigLayout layout;
    protected JComponent container;

    public MigBoxLayoutAdapter(JComponent container) {
        this(new MigLayout(), container);
    }

    public MigBoxLayoutAdapter(MigLayout layout, JComponent container) {
        this.layout = layout;
        this.container = container;
        update();
    }

    @Override
    public LayoutManager getLayout() {
        return layout;
    }

    @Override
    protected void update() {
        updateLayoutConstraints(false);
    }

    private void updateLayoutConstraints(boolean resetExpanded) {
        LC lc = new LC();
        lc.hideMode(2); //  Invisible components will not participate in the layout at all and it will for instance not take up a grid cell
        lc.fill(); // always give all space to components, otherwise align doesn't work
        AC rowConstr = new AC();
        AC colConstr = new AC();

        if (direction.equals(FlowDirection.X)) {
            rowConstr.align("top");
            lc.flowX();
            if (expandedComponent != null || resetExpanded) {
                adjustExpanding(lc, colConstr);
            }
        } else {
            lc.flowY();
            if (expandedComponent != null || resetExpanded) {
                adjustExpanding(lc, rowConstr);
            }
        }

        lc.setInsets(MigLayoutHelper.makeInsets(margins));

        if (!spacing) {
            if (direction.equals(FlowDirection.X)) {
                lc.gridGapX("0");
            } else {
                lc.gridGapY("0");
            }
        }

        if (isDebug())
            lc.debug(1000);

        layout.setLayoutConstraints(lc);
        layout.setRowConstraints(rowConstr);
        layout.setColumnConstraints(colConstr);
    }

    @Override
    public void resetExpanded() {
        expandedComponent = null;
        updateLayoutConstraints(true);
    }

    private void adjustExpanding(LC lc, AC ac) {
        Component[] components = container.getComponents();
        for (int i = 0; i < components.length; i++) {
            if (expandedComponent == null
                    || expandedComponent == components[i]) {
                ac.fill(i);
            } else {
                ac.size("min!", i);
            }
        }
        lc.fill();
    }

    @Override
    public Object getCaptionConstraints(com.haulmont.cuba.gui.components.Component component) {
        CC cc = new CC();
        cc.split(2);
        cc.width("min!");
        cc.height("min!");
        MigLayoutHelper.applyAlignment(cc, component.getAlignment());
        return cc;
    }

    @Override
    public void expand(Component component, String height, String width) {
        super.expand(component, height, width);

        Object cc = layout.getComponentConstraints(component);
        if (cc instanceof CC) {
            if (direction == null || direction == BoxLayoutAdapter.FlowDirection.X
                    && (StringUtils.isEmpty(height) || "-1px".equals(height) || height.endsWith("%"))) {
                MigLayoutHelper.applyWidth((CC) cc, 100, SizeUnit.PERCENTAGE, true);
            }
            if (direction == null || direction == BoxLayoutAdapter.FlowDirection.Y
                    && (StringUtils.isEmpty(width) || "-1px".equals(width) || width.endsWith("%"))) {
                MigLayoutHelper.applyHeight((CC) cc, 100, SizeUnit.PERCENTAGE, true);
            }

        } else
            cc = MigLayoutHelper.getExpandConstraints(width, height, direction);
        layout.setComponentConstraints(component, cc);
    }

    @Override
    public void updateConstraints(JComponent component, Object constraints) {
        if (component == expandedComponent) {
            expand(component);
        } else {
            layout.setComponentConstraints(component, constraints);
            update();
        }
    }

    @Override
    public CC getConstraints(com.haulmont.cuba.gui.components.Component component) {
        return MigLayoutHelper.getConstraints(component);
    }
}