

package org.pentaho.di.core.gui;

import java.util.List;

import org.pentaho.di.core.AddUndoPositionInterface;

public class SnapAllignDistribute
{
    private List<? extends GUIPositionInterface> elements;
    private AddUndoPositionInterface addUndoPositionInterface;
    private int[] indices;
    private Redrawable redrawable;
    private UndoInterface undoInterface;
    
    public SnapAllignDistribute(UndoInterface undoInterface, List<? extends GUIPositionInterface> elements, int[] indices, AddUndoPositionInterface addUndoPositionInterface, Redrawable redrawable)
    {
        this.undoInterface = undoInterface;
        this.elements = elements;
        this.indices = indices;
        this.addUndoPositionInterface = addUndoPositionInterface;
        this.redrawable = redrawable;
    }
    
    public void snaptogrid(int size)
    {
        if (elements.isEmpty()) return;

        // First look for the minimum x coordinate...

        GUIPositionInterface elemArray[] = new GUIPositionInterface[elements.size()];
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface positionInterface = elements.get(i);

            elemArray[i] = positionInterface;
            Point p = positionInterface.getLocation();
            before[i] = new Point(p.x, p.y);

            // What's the modulus ?
            int dx = p.x % size;
            int dy = p.y % size;

            // Correct the location to the nearest grid line!
            // This means for size = 10
            // x = 3: dx=3, dx<=5 --> x=3-3 = 0;
            // x = 7: dx=7, dx> 5 --> x=3+10-3 = 10;
            // x = 10: dx=0, dx<=5 --> x=10-0 = 10;

            if (dx > size / 2)
                p.x += size - dx;
            else
                p.x -= dx;
            if (dy > size / 2)
                p.y += size - dy;
            else
                p.y -= dy;
            after[i] = new Point(p.x, p.y);
        }

        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }

    public void allignleft()
    {
        if (elements.isEmpty()) return;

        GUIPositionInterface elemArray[] = elements.toArray(new GUIPositionInterface[elements.size()]);
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        int min = 99999;

        // First look for the minimum x coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);
            Point p = element.getLocation();
            if (p.x < min) min = p.x;
        }

        // Then apply the coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);

            Point p = element.getLocation();
            before[i] = new Point(p.x, p.y);
            element.setLocation(min, p.y);
            after[i] = new Point(min, p.y);
        }
        
        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }

    public void allignright()
    {
        if (elements.isEmpty()) return;

        GUIPositionInterface elemArray[] = elements.toArray(new GUIPositionInterface[elements.size()]);
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        int max = -99999;

        // First look for the maximum x coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);

            Point p = element.getLocation();
            if (p.x > max) max = p.x;
        }
        // Then apply the coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface stepMeta = elements.get(i);

            Point p = stepMeta.getLocation();
            before[i] = new Point(p.x, p.y);
            stepMeta.setLocation(max, p.y);
            after[i] = new Point(max, p.y);
        }
        
        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }

    public void alligntop()
    {
        if (elements.isEmpty()) return;

        GUIPositionInterface elemArray[] = elements.toArray(new GUIPositionInterface[elements.size()]);
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        int min = 99999;

        // First look for the minimum y coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);
            Point p = element.getLocation();
            if (p.y < min) min = p.y;
        }
        // Then apply the coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);
            
            Point p = element.getLocation();
            before[i] = new Point(p.x, p.y);
            element.setLocation(p.x, min);
            after[i] = new Point(p.x, min);
        }
        
        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }

    public void allignbottom()
    {
        if (elements.isEmpty()) return;

        GUIPositionInterface elemArray[] = elements.toArray(new GUIPositionInterface[elements.size()]);
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        int max = -99999;

        // First look for the maximum y coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);

            Point p = element.getLocation();
            if (p.y > max) max = p.y;
        }
        
        // Then apply the coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);

            Point p = element.getLocation();
            before[i] = new Point(p.x, p.y);
            element.setLocation(p.x, max);
            after[i] = new Point(p.x, max);
        }
        
        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }

    public void distributehorizontal()
    {
        if (elements.size() <= 1) return;

        GUIPositionInterface elemArray[] = elements.toArray(new GUIPositionInterface[elements.size()]);
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        int min = 99999;
        int max = -99999;

        int order[] = new int[elements.size()];

        // First look for the minimum & maximum x coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);

            Point p = element.getLocation();
            if (p.x < min) min = p.x;
            if (p.x > max) max = p.x;
            order[i] = i;
        }

        // Difficult to keep the steps in the correct order.
        // If you just set the x-coordinates, you get special effects.
        // Best is to keep the current order of things.
        // First build an arraylist and store the order there.
        // Then sort order[], based upon the coordinate of the step.
        for (int i = 0; i < elements.size(); i++)
        {
            for (int j = 0; j < elements.size() - 1; j++)
            {
                Point p1 = (elements.get(order[j])).getLocation();
                Point p2 = (elements.get(order[j+1])).getLocation();
                if (p1.x > p2.x) // swap
                {
                    int dummy = order[j];
                    order[j] = order[j + 1];
                    order[j + 1] = dummy;

                    dummy = indices[j];
                    indices[j] = indices[j + 1];
                    indices[j + 1] = dummy;
                }
            }
        }

        // The distance between two steps becomes.
        int distance = (max - min) / (elements.size() - 1);

        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(order[i]);
            
            Point p = element.getLocation();
            before[i] = new Point(p.x, p.y);
            p.x = min + (i * distance);
            after[i] = new Point(p.x, p.y);
            elemArray[i] = element;
        }

        // Undo!
        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }

    public void distributevertical()
    {
        if (elements.size() <= 1) return;

        GUIPositionInterface elemArray[] = elements.toArray(new GUIPositionInterface[elements.size()]);
        
        Point before[] = new Point[elements.size()];
        Point after[] = new Point[elements.size()];

        int min = 99999;
        int max = -99999;

        int order[] = new int[elements.size()];

        // First look for the minimum & maximum y coordinate...
        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(i);

            Point p = element.getLocation();
            if (p.y < min) min = p.y;
            if (p.y > max) max = p.y;
            order[i] = i;
        }

        // Difficult to keep the steps in the correct order.
        // If you just set the y-coordinates, you get special effects.
        // Best is to keep the current order of things.
        // First build an arraylist and store the order there.
        // Then sort order[], based upon the coordinate of the step.
        for (int i = 0; i < elements.size(); i++)
        {
            for (int j = 0; j < elements.size() - 1; j++)
            {
                Point p1 = (elements.get(order[j])).getLocation();
                Point p2 = (elements.get(order[j+1])).getLocation();
                if (p1.y > p2.y) // swap
                {
                    int dummy = order[j];
                    order[j] = order[j + 1];
                    order[j + 1] = dummy;
                    
                    dummy = indices[j];
                    indices[j] = indices[j + 1];
                    indices[j + 1] = dummy;
                }
            }
        }

        // The distance between two steps becomes.
        int distance = (max - min) / (elements.size() - 1);

        for (int i = 0; i < elements.size(); i++)
        {
            GUIPositionInterface element = elements.get(order[i]);

            Point p = element.getLocation();
            before[i] = new Point(p.x, p.y);
            p.y = min + (i * distance);
            after[i] = new Point(p.x, p.y);
            elemArray[i] = element;
        }

        // Undo!
        if (addUndoPositionInterface!=null) addUndoPositionInterface.addUndoPosition(undoInterface, elemArray, indices, before, after);
        redrawable.redraw();
    }
}
