package cnp.ew.layout;

import java.awt.*;
import java.util.*;

import cnp.ew.lightweight.*;

public class CpAttachments
{
    // Use preferred size as an offset from the opposite side
    public static final int ATTACH_NONE=0;

    // Use offset as a distance from the parent's opposite side
    public static final int ATTACH_PARENT=1;

    // Use offset as a distance from the parent's same side
    public static final int ATTACH_PARENT_OPPOSITE=2;

    // Use offset as a distance from self's opposide side
    public static final int ATTACH_SELF=3;

    // Use offset as a distance from the given sibling's opposite side
    public static final int ATTACH_SIBLING=4;

    // Use offset as a distance from the given sibling's same side
    public static final int ATTACH_SIBLING_OPPOSITE=5;

    // Use offset as a percentage distance from parent's left or top
    public static final int ATTACH_POSITION=6;

    // Center the side relative to the parent in this orientation; offset will be added.
    public static final int CENTER_PARENT=7;

    // Center the side relative to the sibling in this orientation; offset will be added.
    public static final int CENTER_SIBLING=8;

    public int leftOffset=0;
    public int rightOffset=0;
    public int topOffset=0;
    public int bottomOffset=0;
    public int leftAttachmentType=ATTACH_NONE;
    public int rightAttachmentType=ATTACH_NONE;
    public int topAttachmentType=ATTACH_NONE;
    public int bottomAttachmentType=ATTACH_NONE;
    public int width = -1;
    public int height = -1;
    public CpLightweightComponent leftSibling, rightSibling, topSibling, bottomSibling;

    public CpAttachments()
    {
        super();
    }

    public CpAttachments(int left, int top, int right, int bottom)
    {
        super();
        if (left >= 0) {
            setLeftAttachment(left);
        }
        if (top >= 0) {
            setTopAttachment(top);
        }
        if (right >= 0) {
            setRightAttachment(right);
        }
        if (bottom >=0) {
            setBottomAttachment(bottom);
        }
    }


    public void setHorizontalCentering()
    {
        setHorizontalCentering(CENTER_PARENT, 0);
    }

    public void setHorizontalCentering(int offset)
    {
        setHorizontalCentering(CENTER_PARENT, offset);
    }

    public void setHorizontalCentering(CpLightweightComponent sibling)
    {
        setHorizontalCentering(CENTER_SIBLING, 0, sibling);
    }

    public void setHorizontalCentering(CpLightweightComponent sibling, int offset)
    {
        setHorizontalCentering(CENTER_SIBLING, offset, sibling);
    }

    public void setHorizontalCentering(int attachmentType, int offset)
    {
        leftAttachmentType = attachmentType;
        leftOffset = offset;
    }

    public void setHorizontalCentering(int attachmentType, int offset, CpLightweightComponent sibling)
    {
        setHorizontalCentering(attachmentType, offset);
        setHorizontalCenteringSibling(sibling);
    }

    public void setHorizontalCenteringSibling(CpLightweightComponent c)
    {
        leftSibling = c;
    }

    public void setVerticalCentering()
    {
        setVerticalCentering(CENTER_PARENT, 0);
    }

    public void setVerticalCentering(int offset)
    {
        setVerticalCentering(CENTER_PARENT, offset);
    }

    public void setVerticalCentering(CpLightweightComponent sibling)
    {
        setVerticalCentering(CENTER_SIBLING, 0, sibling);
    }

    public void setVerticalCentering(CpLightweightComponent sibling, int offset)
    {
        setVerticalCentering(CENTER_SIBLING, offset, sibling);
    }

    public void setVerticalCentering(int attachmentType, int offset)
    {
        topAttachmentType = attachmentType;
        topOffset = offset;
    }

    public void setVerticalCentering(int attachmentType, int offset, CpLightweightComponent sibling)
    {
        setVerticalCentering(attachmentType, offset);
        setVerticalCenteringSibling(sibling);
    }

    public void setVerticalCenteringSibling(CpLightweightComponent c)
    {
        topSibling = c;
    }

    public void setWidth(int width)
    {
        this.width = width;
    }

    public void setHeight(int height)
    {
        this.height = height;
    }

    public void setLeftAttachment(int attachmentOffset)
    {
        setLeftAttachment(ATTACH_PARENT, attachmentOffset);
    }

    public void setLeftAttachment(int attachmentOffset, CpLightweightComponent c)
    {
        setLeftAttachment(ATTACH_SIBLING, attachmentOffset, c);
    }

    public void setLeftAttachment(int attachmentType, int attachmentOffset)
    {
        leftAttachmentType = attachmentType;
        leftOffset = attachmentOffset;
    }

    public void setLeftAttachment(int attachmentType, int attachmentOffset, CpLightweightComponent sibling) {
        setLeftAttachment(attachmentType, attachmentOffset);
        setLeftSibling(sibling);
    }

    public void setLeftSibling(CpLightweightComponent sibling) {
        leftSibling = sibling;
    }

    CpLightweightComponent getLeftSibling()
    {
        return leftSibling;
    }

    public void setRightAttachment(int attachmentOffset)
    {
        setRightAttachment(ATTACH_PARENT, attachmentOffset);
    }

    public void setRightAttachment(int attachmentOffset, CpLightweightComponent c)
    {
        setRightAttachment(ATTACH_SIBLING, attachmentOffset, c);
    }

    public void setRightAttachment(int attachmentType, int attachmentOffset)
    {
        rightAttachmentType = attachmentType;
        rightOffset = attachmentOffset;
    }


    public void setRightAttachment(int attachmentType, int attachmentOffset, CpLightweightComponent sibling) {
        setRightAttachment(attachmentType, attachmentOffset);
        setRightSibling(sibling);
    }

    public void setRightSibling(CpLightweightComponent sibling) {
        rightSibling = sibling;
    }

    CpLightweightComponent getRightSibling()
    {
        return rightSibling;
    }

    public void setTopAttachment(int attachmentOffset)
    {
        setTopAttachment(ATTACH_PARENT, attachmentOffset);
    }

    public void setTopAttachment(int attachmentOffset, CpLightweightComponent c)
    {
        setTopAttachment(ATTACH_SIBLING, attachmentOffset, c);
    }

    public void setTopAttachment(int attachmentType, int attachmentOffset)
    {
        topAttachmentType = attachmentType;
        topOffset = attachmentOffset;
    }

    public void setTopAttachment(int attachmentType, int attachmentOffset, CpLightweightComponent sibling) {
        setTopAttachment(attachmentType, attachmentOffset);
        setTopSibling(sibling);
    }

    public void setTopSibling(CpLightweightComponent sibling) {
        topSibling = sibling;
    }

    CpLightweightComponent getTopSibling()
    {
        return topSibling;
    }

    public void setBottomAttachment(int attachmentOffset)
    {
        setBottomAttachment(ATTACH_PARENT, attachmentOffset);
    }

    public void setBottomAttachment(int attachmentOffset, CpLightweightComponent c)
    {
        setBottomAttachment(ATTACH_SIBLING, attachmentOffset, c);
    }

    public void setBottomAttachment(int attachmentType, int attachmentOffset)
    {
        bottomAttachmentType = attachmentType;
        bottomOffset = attachmentOffset;
    }

    public void setBottomAttachment(int attachmentType, int attachmentOffset, CpLightweightComponent sibling) {
        setBottomAttachment(attachmentType, attachmentOffset);
        setBottomSibling(sibling);
    }

    public void setBottomSibling(CpLightweightComponent sibling) {
        bottomSibling = sibling;
    }

    CpLightweightComponent getBottomSibling()
    {
        return bottomSibling;
    }


    public Rectangle getRectangle(
        Dimension preferredSize,
        Rectangle currentRect,
        Dimension parentExtent,
        Point leftSiblingLeftAndRight,
        Point rightSiblingLeftAndRight,
        Point topSiblingTopAndBottom,
        Point bottomSiblingTopAndBottom)
    {
        Point leftAndWidth, topAndHeight;

        leftAndWidth = getOppositePositions(
            leftAttachmentType,
            rightAttachmentType,
            leftOffset,
            rightOffset,
            leftSiblingLeftAndRight,
            rightSiblingLeftAndRight,
            width,
            preferredSize.width,
            parentExtent.width,
            currentRect.x,
            currentRect.x + currentRect.width);


        topAndHeight = getOppositePositions(
            topAttachmentType,
            bottomAttachmentType,
            topOffset,
            bottomOffset,
            topSiblingTopAndBottom,
            bottomSiblingTopAndBottom,
            height,
            preferredSize.height,
            parentExtent.height,
            currentRect.y,
            currentRect.y + currentRect.height);
        return new Rectangle(leftAndWidth.x, topAndHeight.x, leftAndWidth.y, topAndHeight.y);
    }



    Point getOppositePositions(
        int leftOrTopType,
        int rightOrBottomType,
        int leftOrTopOffset,
        int rightOrBottomOffset,
        Point leftOrTopSiblingLeftAndRightOrTopAndBottom,
        Point rightOrBottomSiblingLeftAndRightOrTopAndBottom,
        int widthOrHeight,
        int preferredWidthOrHeight,
        int parentWidthOrHeight,
        int currentLeftOrTop,
        int currentRightOrBottom)
    {
        int leftOrTop, rightOrBottom;

        switch (leftOrTopType) {
        // handle ATTACH_NONE and ATTACH_SELF after both have been calculated;
        // initialize it just to shut the compiler up.
        case ATTACH_NONE:
        case ATTACH_SELF:
            leftOrTop = 0;
            break;
        case ATTACH_PARENT:
            leftOrTop = leftOrTopOffset;
            break;
        case ATTACH_PARENT_OPPOSITE:
            leftOrTop = parentWidthOrHeight - leftOrTopOffset;
            break;
        case ATTACH_SIBLING:
            leftOrTop = leftOrTopSiblingLeftAndRightOrTopAndBottom.y + leftOrTopOffset;
            break;
        case ATTACH_SIBLING_OPPOSITE:
            leftOrTop = leftOrTopSiblingLeftAndRightOrTopAndBottom.x + leftOrTopOffset;
            break;
        case ATTACH_POSITION:
            leftOrTop = (parentWidthOrHeight * leftOrTopOffset) / 100;
            break;
        // the following two assume that the rightOrBottom attachment types are ATTACH_NONE.
        case CENTER_PARENT:
            if (widthOrHeight >= 0) {
                leftOrTop = (parentWidthOrHeight - widthOrHeight) / 2 + leftOrTopOffset;
            } else {
                leftOrTop = (parentWidthOrHeight - preferredWidthOrHeight) / 2 + leftOrTopOffset;
            }
            break;
        case CENTER_SIBLING:
            int siblingLeftOrTop = leftOrTopSiblingLeftAndRightOrTopAndBottom.x;
            int siblingRightOrBottom = leftOrTopSiblingLeftAndRightOrTopAndBottom.y;
            if (widthOrHeight >= 0) {
                leftOrTop = (siblingLeftOrTop + (siblingRightOrBottom - siblingLeftOrTop - widthOrHeight) / 2) + leftOrTopOffset;
            } else {
                leftOrTop = (siblingLeftOrTop + (siblingRightOrBottom - siblingLeftOrTop - preferredWidthOrHeight) / 2) + leftOrTopOffset;
            }
            break;
        default:
            throw new IllegalArgumentException("invalid attachment type");
        }

        switch (rightOrBottomType) {
        // handle ATTACH_NONE  and ATTACH_SELF after both have been calculated;
        // initialize it just to shut the compiler up.
        case ATTACH_NONE:
        case ATTACH_SELF:
            rightOrBottom = 0;
            break;
        case ATTACH_PARENT:
            rightOrBottom = parentWidthOrHeight - rightOrBottomOffset;
            break;
        case ATTACH_PARENT_OPPOSITE:
            rightOrBottom = rightOrBottomOffset;
            break;
        case ATTACH_SIBLING:
            rightOrBottom = rightOrBottomSiblingLeftAndRightOrTopAndBottom.x - rightOrBottomOffset;
            break;
        case ATTACH_SIBLING_OPPOSITE:
            rightOrBottom = rightOrBottomSiblingLeftAndRightOrTopAndBottom.y - rightOrBottomOffset;
            break;
        case ATTACH_POSITION:
            rightOrBottom = (parentWidthOrHeight * rightOrBottomOffset) / 100;
            break;
        default:
            throw new IllegalArgumentException("invalid attachment type");
        }

        if (leftOrTopType == ATTACH_NONE || leftOrTopType == ATTACH_SELF) {
            if (rightOrBottomType == ATTACH_NONE || rightOrBottomType == ATTACH_SELF) {
                throw new IllegalArgumentException("Must have at least one opposing attachment");
            }
            if (leftOrTopType == ATTACH_NONE) {
                if (widthOrHeight >= 0) {
                    leftOrTop = rightOrBottom - widthOrHeight;
                } else {
                    leftOrTop = rightOrBottom - preferredWidthOrHeight;
                }
            } else {
                leftOrTop = rightOrBottom - leftOrTopOffset;
            }
        }
        if (rightOrBottomType == ATTACH_NONE) {
            if (widthOrHeight >= 0) {
                rightOrBottom = leftOrTop + widthOrHeight;
            } else {
                rightOrBottom = leftOrTop + preferredWidthOrHeight;
            }
        } else  if (rightOrBottomType == ATTACH_SELF) {
            rightOrBottom = leftOrTop + rightOrBottomOffset;
        }

        return new Point(leftOrTop, rightOrBottom - leftOrTop);
    }
}

