/*
 * FormatCommand.java
 *
 * Created on 9 mei 2005, 21:32
 * By Robert Lamping
 * Using the Command pattern
 */

package it.businesslogic.ireport.gui.command;
import it.businesslogic.ireport.Band;
import it.businesslogic.ireport.OperationType;
import java.awt.Rectangle;
import it.businesslogic.ireport.ReportElement;
import it.businesslogic.ireport.gui.JReportFrame;
import it.businesslogic.ireport.gui.MainFrame;
import it.businesslogic.ireport.undo.ElementTransformation;
import it.businesslogic.ireport.undo.FormatElementsOperation;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;


// TODO: Try, Catch
// TODO: Describe

/**
 *
 * @author Fourdim
 */
public class FormatCommand implements ICommand {
    static boolean sleepUndo = false;
    
    MainFrame mf = null;
    JReportFrame jrf = null;
    Enumeration e = null;
    ReportElement re = null;
    int operationType = 0;
    int currentElementPosition = 0;
    FormatElementsOperation undoOp = null;
    
    /** Creates a new instance of FormatCommand */
    public FormatCommand() {
    }
    
    public void execute() {
        
        mf = MainFrame.getMainInstance();
        
        if (mf.getJMDIDesktopPane().getSelectedFrame() != null &&
                mf.getJMDIDesktopPane().getSelectedFrame() instanceof JReportFrame) {
            
            // everytime the current selectedFrame must be chosen
            jrf = (JReportFrame) mf.getJMDIDesktopPane().getSelectedFrame();
            
            // TODO: Buttons should listen to number of selectelements and
            // enable or disable themselves.
            if (jrf.getSelectedElements().isEmpty()) {
                return;
            }
            
            if ( preCondition() ){
                re = null;
                
                undoOp = new FormatElementsOperation(jrf, operationType);
                executeDeeper();
                
                //Compulsary:
                postAction();
            }
            
        }
    }
    
    void executeDeeper(){
        resetEnumeration();
        preparation(); // <========= method in subclass is called if present
        
        resetEnumeration();
        processElements();
    }
    
    void processElements(){
        processElements(this.e);
    }
    
    void processElements(Enumeration e){
        currentElementPosition = -1;
        while (e.hasMoreElements()) {
            currentElementPosition++;
            
            re = (ReportElement) e.nextElement();
            // Undo preparation, phase 1 (pre element transition)
            Rectangle oldBounds = new Rectangle( re.getBounds());
            
            // mf.logOnConsole( re.toString() );
            modify();  // <========= method in subclass is called
            
            // adjusting the boundary of the report element
            // to the current position, width and height.
            
            re.updateBounds();
            // Undo preparation, phase 2 (post element transition)
            Rectangle newBounds = new Rectangle( re.getBounds());
            // se FormatCommand.java for undoOp.
            //mf.logOnConsole("NewBounds" + re.toString() + "\n");
            undoOp.addElement(re, oldBounds, newBounds );
        }
    }
    
    void updateElementsNewBound() {
        resetEnumeration();
        int kkk = 0;
        while (e.hasMoreElements()) {
            re = (ReportElement) e.nextElement();
            Rectangle newBounds = new Rectangle( re.getBounds());
            ((ElementTransformation) undoOp.getTransformations().elementAt(kkk)).newBounds = newBounds;
            kkk++;
        }
    }
    
    int getCurrentElementPosition(){
        return currentElementPosition;
    }
    
    void preparation() {
        //dummy
    }
    
    // TODO: Restrict access, make it private check with interface
    void modify() {
        // if the subclass has a method modify then that method will be executed
        // otherwise this one.
        // Fake, the method of the subclass will normally be performed.
    }
    
    void resetEnumeration() {
        e = jrf.getSelectedElements().elements();
    }
    
    boolean preCondition() {
        return true;
    }
    
    void postAction() {
        jrf.getReportPanel().repaint();
        
        if (! sleepUndo ) {
            
            jrf.addUndoOperation(undoOp);
            
            //if (jrf.getSelectedElements().size() > 0) {
            mf.updateDocumentStructureTree(jrf);
            //}
            
            // this part should be move to a listener
            jrf.getReportPanel().repaint();
        }
    }
    
    Vector sortYX( Enumeration enum2 ) {
        Vector myElements = new Vector();
        
        while (enum2.hasMoreElements()) {
            re = (ReportElement) enum2.nextElement();
            // insert this element in the right position...
            if (myElements.size() == 0) {
                myElements.add(re);
            } else {
                
                boolean inserted = false;
                
                for (int i=0; i<myElements.size(); ++i) {
                    ReportElement re2 = (ReportElement)myElements.elementAt(i);
                    if (re.getPosition().y < re2.getPosition().y) {
                        myElements.insertElementAt(re, i);
                        inserted = true;
                        break;
                    } else if (re.getPosition().y == re2.getPosition().y) {
                        if (re.getPosition().x < re2.getPosition().x) {
                            myElements.insertElementAt(re, i);
                            inserted = true;
                            break;
                        }
                    }
                }
                if (!inserted) {
                    myElements.addElement(re);
                }
            }
        }
        return myElements;
    }
    
    Vector sortXY( Enumeration enum2 ) {
        Vector myElements = new Vector();
        
        while (enum2.hasMoreElements()) {
            re = (ReportElement) enum2.nextElement();
            // insert this element in the right position...
            if (myElements.size() == 0) {
                myElements.add(re);
            } else {
                
                boolean inserted = false;
                
                for (int i=0; i<myElements.size(); ++i) {
                    ReportElement re2 = (ReportElement)myElements.elementAt(i);
                    if (re.getPosition().x < re2.getPosition().x) {
                        myElements.insertElementAt(re, i);
                        inserted = true;
                        break;
                    } else if (re.getPosition().x == re2.getPosition().x) {
                        if (re.getPosition().y < re2.getPosition().y) {
                            myElements.insertElementAt(re, i);
                            inserted = true;
                            break;
                        }
                        
                    }
                }
                if (!inserted) {
                    myElements.addElement(re);
                }
            }
        }
        return myElements;
    }
    
    Vector getBandElements(Band b) {
        Vector bandElements = new Vector();
        
        for (Iterator i = jrf.getSelectedElements().iterator(); i.hasNext(); ) {
            ReportElement re = (ReportElement) i.next();
            if (re.getBand() == b) {
                bandElements.add(re);
            }
        }
        return bandElements;
    }
    
    /*
     * getBands() returns a unique list of bands that have selected elements in it.
     **/
    Vector getBands() {
        Vector bands = new Vector();
        
        for (Iterator h = jrf.getSelectedElements().iterator(); h.hasNext(); ) {
            ReportElement bandRe = (ReportElement) h.next();
            if (!bands.contains(bandRe.getBand())) {
                bands.add(bandRe.getBand());
            }
        }
        return bands;
    }
    
    static public FormatCommand getCommand(int operationType) {
        // this must be move to a factory
        // MainFrame.getMainInstance().logOnConsole("" + operationType);
        
        switch (operationType) {
            
            case OperationType.ALIGN_TOP:
                return (new FormatCommandAlignTop());
            case OperationType.ALIGN_BOTTOM:
                return (new FormatCommandAlignBottom());
            case OperationType.ALIGN_LEFT:
                return (new FormatCommandAlignLeft());
            case OperationType.ALIGN_RIGHT:
                return (new FormatCommandAlignRight());
                
            case OperationType.ALIGN_HORIZONTAL_AXIS:
                return (new FormatCommandAlignHorizontalAxis());
            case OperationType.ALIGN_VERTICAL_AXIS:
                return (new FormatCommandAlignVerticalAxis());
                
            case OperationType.ALIGN_CENTER_HORIZONTALLY:
                return (new FormatCommandAlignCenterHorizontally());
            case OperationType.ALIGN_CENTER_VERTICALLY:
                return (new FormatCommandAlignCenterVertically());
            case OperationType.ALIGN_CENTER:
                return (new FormatCommandAlignCenter());
                
            case OperationType.SAME_HEIGHT:
                return (new FormatCommandSameHeight());
            case OperationType.SAME_HEIGHT_MAX:
                return (new FormatCommandSameHeightMax());
            case OperationType.SAME_HEIGHT_MIN:
                return (new FormatCommandSameHeightMin());
                
            case OperationType.SAME_WIDTH:
                return (new FormatCommandSameWidth());
            case OperationType.SAME_WIDTH_MAX:
                return (new FormatCommandSameWidthMax());
            case OperationType.SAME_WIDTH_MIN:
                return (new FormatCommandSameWidthMin());
                
            case OperationType.SAME_SIZE:
                return (new FormatCommandSameSize());
                
                
            case OperationType.ALIGN_TOP_TO_BAND:
                return (new FormatCommandAlignTopToBand());
            case OperationType.ALIGN_BOTTOM_TO_BAND:
                return (new FormatCommandAlignBottomToBand());
            case OperationType.ALIGN_TO_LEFT_MARGIN:
                return (new FormatCommandAlignToLeftMargin());
            case OperationType.ALIGN_TO_RIGHT_MARGIN:
                return (new FormatCommandAlignToRightMargin());
                
            case OperationType.MOVE_TO_LEFT_MARGIN:
                return (new FormatCommandMoveToLeftMargin());
            case OperationType.MOVE_TO_RIGHT_MARGIN:
                return (new FormatCommandMoveToRightMargin());
                
            case OperationType.JOIN_LEFT:
                return (new FormatCommandJoinLeft());
            case OperationType.JOIN_RIGHT:
                return (new FormatCommandJoinRight());
                
            case OperationType.EQUALS_SPACE_H:
                return (new FormatCommandEqualsSpaceH());
                
            case OperationType.EQUALS_SPACE_V:
                return (new FormatCommandEqualsSpaceV());
            case OperationType.INCREASE_SPACE_V:
                return (new FormatCommandIncreaseSpaceV());
                
            case OperationType.DECREASE_SPACE_V:
                return (new FormatCommandDecreaseSpaceV());
            case OperationType.DECREASE_SPACE_H:
                return (new FormatCommandDecreaseSpaceH());
                
            case OperationType.INCREASE_SPACE_H:
                return (new FormatCommandIncreaseSpaceH());
                
            case OperationType.REMOVE_SPACE_V:
                return (new FormatCommandRemoveSpaceV());
                
            case OperationType.ORGANIZE_AS_A_TABLE:     // multicommand
                return (new FormatCommandOrganizeAsATable());
                
            case OperationType.ELEMENT_MAXIMIZE:
                return (new FormatCommandElementMaximize());
                
            case OperationType.ELEMENT_MAXIMIZE_H:
                return (new FormatCommandElementMaximizeH());
                
            case OperationType.ELEMENT_MAXIMIZE_V:
                return (new FormatCommandElementMaximizeV());
                
            case OperationType.CENTER_IN_BAND:
                return (new FormatCommandCenterInBand());
            case OperationType.CENTER_IN_BAND_V:
                return (new FormatCommandCenterInBandV());
            case OperationType.CENTER_IN_BAND_H:
                return (new FormatCommandCenterInBandH());
                
            default: return null;
        }
        
        
    }
    
}