package lectures.composite.objects_shapes;
import util.annotations.WebDocuments;

import util.annotations.StructurePattern;
import util.annotations.StructurePatternNames;
import lectures.graphics.ALine;
import lectures.graphics.AStringShape;
import lectures.graphics.Line;
import lectures.graphics.StringShape;
import bus.uigen.OEFrame;
import bus.uigen.ObjectEditor;

/*
 * The purpose of this class is to draw a scalable Cartesian Plane with labeled X and
 * Y axes.
 * 
 * An editable AxesLength property can be used to magnify and shrink the plane.  
 *
 */
@StructurePattern(StructurePatternNames.BEAN_PATTERN)
@WebDocuments({"Lectures/CompositeObjectsShapes.pptx", "Lectures/CompositeObjectsShapes.pdf", "Videos/CompositeObjectsShapes.avi"})
public class ACartesianPlane implements CartesianPlane {    
    protected int originX, originY;
    protected int axesLength;   
    protected Line xAxis;
    protected Line yAxis;  
    protected StringShape xLabel;
    protected StringShape yLabel;
/*    
 * ACartesianPlane has:
 *   a) only primitive components in its physical structure.
 *   b) only object components in its physical structure.
 *   c) both primitive and object components in its physical structure.
 */
    
    public ACartesianPlane (int theAxesLength, int theOriginX, int theOriginY ) {       
        axesLength = theAxesLength; 
        originX = theOriginX;
        originY = theOriginY;
        /*
         * Creating the initial structure based on the initial axeslength.
         */
       xAxis = new ALine(toXAxisX(), toXAxisY(), axesLength, 0);
       yAxis = new ALine(toYAxisX(), toYAxisY(), 0, axesLength);  
       xLabel = new AStringShape ("X", toXLabelX(), toXLabelY());
       yLabel = new AStringShape ("Y", toYLabelX(), toYLabelY());
    }
/*
 * The constructor of ACartesianPlane:
 *    (a) does not initialize its object variables.
 *    (b) assigns its parameters to its object variables.
 *    (c) creates new instances and assigns them to its object variables.
 *   
 */
   
    public Line getXAxis() {
        System.out.println ("X Axis:" + xAxis);
        return xAxis;
    }
/*
 * (T/F) getAxis() of ACartesianPlane creates and returns a new object each time 
 * it is called.
 */
    public Line getYAxis() {
        return yAxis;
    }    
    public StringShape getXLabel() {
        return xLabel;
    }
    public StringShape getYLabel() {
        return yLabel;
    }
    public int getAxesLength() {
        return axesLength;
    }
    
    /*
     * setAxesLength modifies the graphical components to be consistent with 
     * the new axeslength.  
     */
    public void setAxesLength(int anAxesLength) {
        System.out.println ("New axes length:" + anAxesLength);
        axesLength = anAxesLength;
        xAxis.setWidth(axesLength);
        yAxis.setHeight(axesLength);
        xAxis.setX(toXAxisX());
        xAxis.setY(toXAxisY());
        yAxis.setX(toYAxisX());
        yAxis.setY(toYAxisY());
        xLabel.setX(toXLabelX());
        xLabel.setY(toXLabelY());
        yLabel.setX(toYLabelX());
        yLabel.setY(toYLabelY());
    }
/*
 * Calling setAxesLength in ACartesianPlane, changes the:
 *   (a) object variable xAxis, that is, 
 *       assigns a new object to this variable.
 *   (b) primitive X property of the existing object stored in the xAxis variable. 
 *   (c) None of the above.
 *   
 * Calling setAxesLength in ACartesianPlane changes:
 *      (a)  leaf nodes in the physical structure.
 *      (b)  object nodes in the physical structure.
 *      (c)  None of the above
 */
    
    /*
     * These methods are used for calculating the locations of the line and label objects
     */
    protected int toXAxisX() {
        return originX - axesLength/2;
    }
    protected int toXAxisY() {
        return originY;
    }
    protected int toYAxisX() {
        return originX;
    }
    protected int toYAxisY() {
        return originY - axesLength/2;
    }
    protected int toXLabelX() {
        return originX + axesLength/2;      
    }
    protected int toXLabelY() {
        return originY;     
    }
    protected int toYLabelX() {
        return originX;     
    }
    protected int toYLabelY() {
        return originY - axesLength/2;      
    }
    
    public static void main (String[] args) {
        CartesianPlane aCartesianPlane = 
            new ACartesianPlane(INIT_AXES_LENGTH, INIT_ORIGIN_X, INIT_ORIGIN_Y);
        OEFrame anOEFrame =  ObjectEditor.edit(aCartesianPlane);
        anOEFrame.showTreePanel();
        anOEFrame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        /*
         * set a break point on setter call
         */
        aCartesianPlane.setAxesLength(aCartesianPlane.getAxesLength()*2);
        anOEFrame.refresh();
        // to hide the main panel, you can execute
//      anOEFrame.hideMainPanel();
        
    }   
}
/*
 * Study the class and draw or imagine the logical and physical structure
 * of the instance created by main.
 * 
 * Which properties have setters?    
 * 
 * (T/F) AxesLength is a readonly property of ACartesianPlane.
 * 
 * (T/F) XAxis is readonly property of ACartesianPlane. 
 * 
 * (T/F) All object properties of ACartesianPlane are readonly.
 * 
 * (T/F) XAxis is a stored property of ACartesianPlane, that is, its value
 * is stored in an instance variable.
 * 
 * (T/F) In ACartesianPlane, each time a getter of an object property is called, 
 * a new object is returned.  
 */

/*  
 * 
 * Run in debug mode and stop at the breakpoint, and step into the getter, 
 * step return, and then step into the setter.
 * 
 * Look at the physical structure displayed by the debugger. 
 *  
 * (T/F) xAxesLength is a leaf variable of ACartesianPlane.
 * 
 * (T/F) xAxis is a leaf variable of ACartesianPlane. 
 * 
 * Look at the logical structure displayed by ObjectEditor.
 * 
 * Is the content of the graphics panel predicted?
 *  
 * Is the content of the main panel predicted?
 * 
 * (T/F) Every property of an object is displayed in the ObjectEditor tree panel.
 * 
 * (T/F) Every property of an object is displayed in the main panel.
 * 
 * (T/F) Every property of an object is displayed either in the main panel
 * or the graphics panel.   
 *  
 * Resume the execution to see the behavior of the program. 
 * Edit the AxesLength to call setAxesLength and see the effect.
 * 
 * When the setter above is called, did any of the leaf nodes change in the structure?
. 
 * Did any of the composite nodes change, that is, did they get new children or 
 * lose children?
 * 
 * Look at the console output. Is it what you would predict.
 *
 * Look at the code in setAxesLength and getAxis and review your answers about it.
 * 
 * The next example is more concise but also inefficient: 
 * AnInefficientCartesianPlane
 */