/*************************************************
 *
 * Author: 	Evelyn Lai-Tee Cheok
 *			Department of Electrical Engineering
 *			Center for Telecommunications Research
 *			Schapiro Research Building
 *			Columbia University
 *
 * Email: 	laitee@ctr.columbia.edu
 *
 * Author: 	Chi-Hao Li	
 *			Department of Computer Science
 *			Columbia University
 *
 **************************************************/
import java.awt.*;
import java.lang.*;
import java.io.*;
import java.util.*;
import ObjType;

public class SketchArea extends Canvas {

	public Image offscreenImg;
	public Graphics GC, offscreenG;

	/* search for local moveObj only once */
	public Object moveObj = null;

	/* object to move after receiving remote MOVE request */
	public DrawObject objToMove = null;

	public DrawObject selectedObj = null;

	Stack S1, S2;

	SketchPanel parent;
	ObjPanel objpanel;
	ColorPanel colorpanel;

	TextEntryDlg textDlg;
	String text = null;

	Line wbLine;
	Rect wbRect;
	Circle wbCircle;
	Oval wbOval;
	Text wbText;

	int obj = 0;
	int start = 0;
	int color = 0;

	/**
	 * constructor
	 *
	 *@param _parent parent reference
	 *@return none
	 */

	 SketchArea(Object _parent) {

		super();

		this.parent = (SketchPanel) _parent;
		this.objpanel = parent.obj_panel;
		this.colorpanel = parent.color_panel;

		S1 = new Stack();
		S2 = new Stack();

		//resize(400, 360);
	}

	/**
	 * set border width
	 *
	 *@param none
	 *@return Insets
	 */

	public Insets insets() {
		return new Insets(0, 0, 0, 0);
	}

	/**
	 * member function to handle exposure event and create offscreen buffer
	 *
	 *@param g graphics context
	 *@return void
	 */

	public void paint(Graphics g) {

		System.out.println("REPAINT of SKETCHAREA");
		System.out.println("start = "+start);
		if (start == 0) {
			GC = g;

			//offscreenImg = this.createImage(410, 370);
			offscreenImg = this.createImage(510, 370);
			offscreenG = offscreenImg.getGraphics();
			offscreenG.setColor(Color.blue);
			//offscreenG.draw3DRect(0, 0, 500, 359, true);
			offscreenG.drawRect(0, 0, 500, 359);
			offscreenG.clipRect(0, 0, 500, 359);
			start = 1;
		}
		g.drawImage(offscreenImg, 0, 0, this);

	}

	/** pastes objects from the clipboard.  
	  * @param objToPaste object from the clipboard
	  **/
	public void paste(DrawObject objToPaste) {

		if (objToPaste instanceof Line) {
			Line line = (Line)( ((Line)(objToPaste)).clone() );
			line.paint(offscreenG);
			repaint();
			addStack((Object)line);
			line.send();
		}

		else if (objToPaste instanceof Rect) {
			Rect rect = (Rect)( ((Rect)(objToPaste)).clone() );
			rect.paint(offscreenG);
			repaint();
			addStack((Object)rect);
			rect.send();
		}

		else if (objToPaste instanceof Circle) {
			Circle circle = (Circle)( ((Circle)(objToPaste)).clone() );
			circle.paint(offscreenG);
			repaint();
			addStack((Object)circle);
			circle.send();
		}

		else if (objToPaste instanceof Oval) {
			Oval oval = (Oval)( ((Oval)(objToPaste)).clone() );
			oval.paint(offscreenG);
			repaint();
			addStack((Object)oval);
			oval.send();
		}

		else if (objToPaste instanceof Text) {
			Text textobj = (Text)( ((Text)(objToPaste)).clone() );
			textobj.paint(offscreenG);
			repaint();
			addStack((Object)textobj);
			textobj.send();
			System.out.println("&&&&&&&&& Check parameters sent during paste &&&&&");
			System.out.println("textobj.obj_id = "+textobj.obj_id);
			System.out.println("textobj.x1 = "+textobj.x1);
			System.out.println("textobj.y1 = "+textobj.y1);
			System.out.println("textobj.text_str_len = "+textobj.text.length());
			System.out.println("textobj.text_string = "+textobj.text);
			System.out.println("&&&&&&&&&&&&&&");
		}

	}

	/**
	 * event handler for mouse down
	 *
	 *@param e event instance
	 *@param x x value
	 *@param y y value
	 *@return true
	 */

	public boolean mouseDown(Event e, int x, int y) {

		obj = objpanel.getSelectedObj();
		color = colorpanel.getSelectedCol();

		switch (obj) {
			case ObjType.LINE:
				wbLine = new Line(this, color);
				wbLine.mouseDown(x, y);
				break;
			case ObjType.RECT:
				wbRect = new Rect(this, color);
				wbRect.mouseDown(x, y);
				break;
			case ObjType.CIRCLE:
				wbCircle = new Circle(this, color);
				wbCircle.mouseDown(x, y);
				break;
			case ObjType.OVAL:
				wbOval = new Oval(this, color);
				wbOval.mouseDown(x, y);
				break;
			case ObjType.TEXT:
				textDlg = new TextEntryDlg(this, x, y, color);
				textDlg.show();
				/*if ( textfield.isVisible() )
					proctextfield(x, y, color);
				else {
					textfield.reshape(x, y, 1, 1);
					textfield.setText("");
					textfield.show();
				}
				*/
				break;
			case ObjType.DELETE:
				erase(x, y);
				break;
			case ObjType.MOVE:
				getMoveObject(x, y);
				break;
			case ObjType.SELECT:
				getSelectedObject(x, y);
				break;
		}
		 return true;
	}

	/** Processes text , if any, entered into the textfield, when
	  * mouseDown event has occurred.
	  * @param x x coordinate of mouseDown event.
	  * @param y y coordinate of mouseDown event.
	  * @param color color of text entered.
	  **/

	public void proctextfield(int x, int y, int color, String textStr) {
			if (textStr != null) {
			wbText = new Text( this, textStr, color, 
								getFontMetrics(offscreenG.getFont()) );
			wbText.mouseDown(x, y);
			wbText.paint(offscreenG);
			repaint();
			addStack((Object)wbText);
			wbText.send();
			}
			else
				System.out.println("???????? text in proctextfield is NULL !!!");
	}
	
	/*public void popup(Frame main_parent, String title) {
		dlg = new Dialog(main_parent, title, false);
		dlg.setLayout(new FlowLayout());
		dlg.resize(300,300);
		dlg.add(textfield);
		dlg.add(new Button("OK"));

		dlg.show();
	}

	public boolean handleEvent(Event e) {
		if (e.target instanceof Button) {
			String label = ((Button)e.target).getLabel();
			if (label.equals("OK"))
				dlg.removeAll();
				dlg.hide();
		return true;
		}
		return false;
	}
	*/
	
	/** Processes text , if any, entered into the textfield, when
	  * mouseDown event has occurred.
	  * @param x x coordinate of mouseDown event.
	  * @param y y coordinate of mouseDown event.
	  * @param color color of text entered.
	  **/

	/*public void proctextfield(int x, int y, int color) {
		String text = textfield.getText();

		textfield.setText("");
		textfield.hide();

		if ( text != null ) {
			wbText = new Text(this, text, getStringDim(text), color);
			wbText.mouseDown(x, y);
			wbText.paint(offscreenG);
			addStack((Object)wbText);
		}
	}
	*/

	/**
	 * event handler for house up
	 *
	 *@param e event instance
	 *@param x x value
	 *@param y y value
	 *@return true
	 */

	public boolean mouseUp(Event e, int x, int y) {
		switch (obj) {
			case ObjType.LINE:
			wbLine.mouseUp(x, y);
			wbLine.paint(offscreenG);
			repaint();
			S1.push((Object) wbLine);
			break;
			case ObjType.RECT:
			wbRect.mouseUp(x, y);
			wbRect.paint(offscreenG);
			repaint();
			S1.push((Object) wbRect);
			break;
			case ObjType.CIRCLE:
			wbCircle.mouseUp(x, y);
			wbCircle.paint(offscreenG);
			repaint();
			S1.push((Object) wbCircle);
			break;
			case ObjType.OVAL:
			wbOval.mouseUp(x, y);
			wbOval.paint(offscreenG);
			repaint();
			S1.push((Object) wbOval);
			break;
			case ObjType.MOVE:
			if (moveObj != null)
				moveUp(x, y);
			break;
		}
		return true;
	}


	/**
	 *
	 * execute erase and repaint the object while moving
	 *
	 *@param x x value
	 *@param y y value
	 *@return void
	 */

	void moveUp(int x, int y) {
		DrawObject mo = (DrawObject) moveObj;
		int type = mo.getType();

		if (!S1.empty()) {
			switch (type) {
				case ObjType.LINE:
				((Line) moveObj).moveUP(offscreenG, x, y);
				repaint();
				break;
				case ObjType.RECT:
				((Rect) moveObj).moveUP(offscreenG, x, y);
				repaint();
				break;
				case ObjType.CIRCLE:
				((Circle) moveObj).moveUP(offscreenG, x, y);
				repaint();
				break;
				case ObjType.OVAL:
				((Oval) moveObj).moveUP(offscreenG, x, y);
				repaint();
				break;
				case ObjType.TEXT:
				((Text) moveObj).moveUP(offscreenG, x, y);
				repaint();
				break;
				case ObjType.IMAGE:
				((Img) moveObj).moveUP(offscreenG, x, y);
				repaint();
				break;
			}
		}
		 moveObj = null;

	}

	/**
	 * function call to drag object when moving the object
	 *
	 *@param x x value
	 *@param y y value
	 *@return void
	 */

	void moving(int x, int y) {
		DrawObject mo = (DrawObject) moveObj;
		int type = mo.getType();

		Graphics g = getGraphics();

		if (!S1.empty()) {
			switch (type) {
				case ObjType.LINE:
				((Line) moveObj).moving(g, x, y);
				break;
				case ObjType.RECT:
				((Rect) moveObj).moving(g, x, y);
				break;
				case ObjType.CIRCLE:
				((Circle) moveObj).moving(g, x, y);
				break;
				case ObjType.OVAL:
				((Oval) moveObj).moving(g, x, y);
				break;
				case ObjType.TEXT:
				((Text) moveObj).moving(g, x, y);
				break;
				case ObjType.IMAGE:
				((Img) moveObj).moving(g, x, y);
				break;
			}
		}
	}

	/** Checks whether desired object from the stack is a Line object. 
	  * @param top topmost object on the graphics object stack.
	  * @param x x coordinate of mouse event.
	  * @param y y coordinate of mouse event.
	  * @return true when selected object is a line.
	  **/

	public boolean isLine(DrawObject top, int x, int y) {
		Line line = (Line) top;
		float seg1 = (x - line.x1) * (x - line.x1) + (y - line.y1) * (y - line.y1);
		float seg2 = (x - line.x2) * (x - line.x2) + (y - line.y2) * (y - line.y2);

		float len = (line.x1 - line.x2) * (line.x1 - line.x2) +
					(line.y1 - line.y2) * (line.y1 - line.y2);

		if ((seg1 + seg2) - len < 1) 
			return true;
		else 
			return false;
	}

	/** Checks whether desired object from the stack is a Rectangle.
	  * @param top topmost object on the graphics object stack.
	  * @param x x coordinate of mouse event.
	  * @param y y coordinate of mouse event.
	  * @return true when selected object is a rectangle.
	  **/

	public boolean isRect(DrawObject top, int x, int y) {
		Rect rect = (Rect) top;
		boolean h = (y >= rect.y1 && y <= (rect.y1 + rect.height));
		boolean w = (x >= rect.x1 && x <= (rect.x1 + rect.width));
		if (h && w)
			return true;
			else
		return false;
	}

	/** Checks whether desired object from the stack is a Circle object.
      * @param top topmost object on the graphics object stack.
	  * @param x x coordinate of mouse event.
	  * @param y y coordinate of mouse event.
	  * @return true when selected object is a circle.
	  **/
	 
	public boolean isCircle(DrawObject top, int x, int y) {
		Circle circle = (Circle) top;
		int cx = circle.x1 + circle.width / 2;
		int cy = circle.y1 + circle.height / 2;
		float r = circle.width / 2;

		float val = (x - cx) * (x - cx) +
					(y - cy) * (y - cy) - r * r;
		
		if (val < 0)
			return true;
		else
			return false;
	}

	/** Checks whether desired object from the stack is an Oval object.
      * @param top topmost object on the graphics object stack.
	  * @param x x coordinate of mouse event.
	  * @param y y coordinate of mouse event.
	  * @return true when selected object is a oval.
	  **/

	public boolean isOval(DrawObject top, int x, int y) {
		Oval oval = (Oval) top;

		float a = oval.width / (float) 2.0;
		float b = oval.height / (float) 2.0;

		float dx = a + oval.x1;
		float dy = b + oval.y1;

		float va = b * b * (x - dx) * (x - dx) +
					a * a * (y - dy) * (y - dy) -
					a * a * b * b;
		if (va < 0)
			return true;
		else
			return false;
	}

	/** Checks whether desired object from the stack is a Text object.
      * @param top topmost object on the graphics object stack.
	  * @param x x coordinate of mouse event.
	  * @param y y coordinate of mouse event.
	  * @return true when selected object is a text string.
	  **/

	public boolean isText(DrawObject top, int x, int y) {
		Text textObj = (Text) top;

		boolean h = ( (y <= textObj.y1) && (y >= (textObj.y1 - textObj.height)) );
		boolean w = ( (x >= textObj.x1) && (x <= (textObj.x1 + textObj.width)) );
	
		if ( h && w )
			return true;
		else
			return false;
	}

	/** Checks whether desired object from the stack is an Image.
      * @param top topmost object on the graphics object stack.
	  * @param x x coordinate of mouse event.
	  * @param y y coordinate of mouse event.
	  * @return true when selected object is an image.
	  **/

	public boolean isImage(DrawObject top, int x, int y) {
		Img imgObj = (Img)top;

		boolean h = ( (y >= imgObj.y1) && (y <= (imgObj.y1 + imgObj.imageHeight)) );
		boolean w = ( (x >= imgObj.x1) && (x <= (imgObj.x1 + imgObj.imageWidth)) );
	
		if ( h && w )
			return true;
		else
			return false;
	}

	/** Gets selected object from the graphics object stack **/

	void getSelectedObject(int x, int y) {
		DrawObject top;
		int type = 0, popcount = 0;
		boolean found = false;

		while (!found && !S1.empty()) {
			popcount++;

			System.err.println(popcount);

			//switch stack
			top = (DrawObject)
				S1.pop();

			type = top.getType();

			switch (type) {
			case ObjType.LINE:

				if ( isLine(top, x, y) ) {
					found = true;
					System.err.println("found line");
					selectedObj = top;
				}
				 S2.push(top);

				break;

			case ObjType.RECT:

				if ( isRect(top, x, y) ) {
					found = true;
					System.err.println("found rect");
					selectedObj = top;
				}
				S2.push(top);

				break;

			case ObjType.CIRCLE:

				if ( isCircle(top, x ,y) ) {
					found = true;
					System.err.println("found circle");
					selectedObj = top;
				}
				S2.push(top);

				break;

			case ObjType.OVAL:

				if ( isOval(top, x , y) ) {
					found = true;
					System.err.println("found oval");
					selectedObj = top;
				}
				S2.push(top);

				break;
	 		case ObjType.TEXT:

				if ( isText(top, x, y) ) {
					found = true;
					System.err.println("found text");
					selectedObj = top;
					System.out.println(" ********** TEXT selected !! ************");
					System.out.println(" Object ID = "+((Text)top).obj_id);
					System.out.println(" x1 = "+((Text)top).x1);
					System.out.println(" y1 = "+((Text)top).y1);
					System.out.println(" text_str_len = "+((Text)top).text.length());
					System.out.println(" text string = "+((Text)top).text);
					System.out.println(" *********************");

				}
				S2.push(top);
				break;

			}
		}
		while (popcount-- > 0)
			S1.push(S2.pop());
	}

	/**
	 * distingush which object is selected by mouse position
	 *
	 *@param x x value
	 *@param y y value
	 *@return void
	 */

	void getMoveObject(int x, int y) {
		DrawObject top;
		int type = 0, popcount = 0;
		boolean found = false;

		while (!found && !S1.empty()) {
			popcount++;

			System.err.println(popcount);

			//switch stack
			top = (DrawObject)
				S1.pop();

			type = top.getType();

			switch (type) {
			case ObjType.LINE:

				if ( isLine(top, x, y) ) {
					found = true;
					moveObj = top;
					((Line) moveObj).erase(offscreenG, false);
				}
				 S2.push(top);

				break;

			case ObjType.RECT:

				if ( isRect(top, x, y) ) {
					found = true;
					System.err.println("found rect");
					moveObj = top;
					((Rect) moveObj).setBaseDist(offscreenG, x, y);
					repaint();
					//((Rect) moveObj).erase(offscreenG);
				}
				S2.push(top);

				break;

			case ObjType.CIRCLE:

				if ( isCircle(top, x ,y) ) {
					found = true;
					System.err.println("found circle");
					moveObj = top;
					((Circle) moveObj).erase(offscreenG, false);
				}
				S2.push(top);

				break;

			case ObjType.OVAL:

				if ( isOval(top, x , y) ) {
					found = true;
					System.err.println("found oval");
					moveObj = top;
					((Oval) moveObj).erase(offscreenG, false);
				}
				S2.push(top);

				break;
				
			case ObjType.TEXT:

				if ( isText(top, x, y) ) {
					found = true;
					moveObj = top;
					((Text) moveObj).setBaseDist(offscreenG, x, y);
					repaint();
				}
				S2.push(top);

				break;

			case ObjType.IMAGE:

				if ( isImage(top, x, y) ) {
					found = true;
					moveObj = top;
					((Img) moveObj).setBaseDist(offscreenG, x, y);
					repaint();
					System.out.println("found image object at beginning of move !");
				}
				S2.push(top);

				break;
			}
		}
		while (popcount-- > 0)
			S1.push(S2.pop());
	}

	/**
	 * function to delete a selected object
	 *
	 *@param x x value
	 *@param y y value
	 *@return void
	 */

	void erase(int x, int y) {
		DrawObject top;
		int type = 0, popcount = 0;
		boolean found = false;

		while (!found && !S1.empty()) {
			popcount++;

			System.err.println(popcount);

			//switch stack
			top = (DrawObject)
				S1.pop();

			type = top.getType();

			switch (type) {
				case ObjType.LINE:

				if ( isLine(top, x, y) ) {
					found = true;
					popcount--;
					((Line)top).erase(offscreenG, true);
					repaint();
				} else {
					S2.push(top);
				}
				break;

			case ObjType.RECT:
				
				if ( isRect(top, x, y) ) {
					found = true;
					popcount--;
					((Rect)top).erase(offscreenG, true);
					repaint();
				} else {
					S2.push(top);
				}
				break;

			case ObjType.CIRCLE:

				if ( isCircle(top, x, y) ) {
					found = true;
					System.err.println("found circle");
					popcount--;
					((Circle)top).erase(offscreenG, true);
					repaint();
				} else {
					S2.push(top);
				}
				break;

			case ObjType.OVAL:

				if ( isOval(top, x, y) ) {
					found = true;
					System.err.println("found oval");
					popcount--;
					((Oval)top).erase(offscreenG, true);
					repaint();
				} else {
					S2.push(top);
				}
				break;

			case ObjType.TEXT:

				if ( isText(top, x, y) ) {
					found = true;
					System.err.println("found oval");
					popcount--;
					((Text)top).erase(offscreenG, true);
					repaint();
				} else {
					S2.push(top);
				}
				break;

			case ObjType.IMAGE:

				if ( isImage(top, x, y) ) {
					found = true;
					System.err.println("found image");
					popcount--;
					((Img)top).erase(offscreenG, true);
					repaint();
				} else {
					S2.push(top);
				}
				break;
			}
		}
		while (popcount-- > 0)
			S1.push(S2.pop());
	}
	/**
	 * stack manipulation
	 *
	 *@param count number of poped out objects
	 *@return void
	 */

	private void stackOp(int count) {
		while (count-- > 0)
			S1.push(S2.pop());
	}

	/**
	 * event handler for mouse drag
	 *
	 *@param e event type
	 *@param x x value
	 *@param y y value
	 *@return true
	 */

	public boolean mouseDrag(Event e, int x, int y) {

		Graphics g = getGraphics();

		switch (obj) {
			case ObjType.LINE:
				wbLine.mouseDrag(x, y);
				wbLine.clear(g);
				break;
			case ObjType.RECT:
				wbRect.mouseDrag(x, y);
				wbRect.clear(g);
				break;
			case ObjType.CIRCLE:
				wbCircle.mouseDrag(x, y);
				wbCircle.clear(g);
				break;
			case ObjType.OVAL:
				wbOval.mouseDrag(x, y);
				wbOval.clear(g);
				break;
			case ObjType.MOVE:
				if (moveObj != null)
					moving(x, y);
				break;
		}
		 return true;
	}

	/**
	 * process data passed from network, the data contains essential parameter for  
	 * various drawing objects
	 *
	 *@param buf buffer in bytes to hold the parameters
	 *@return void
	 */

	public void processInData(byte[] buf) {
		int Obj_type = 0;;
		byte[] obj_buf = new byte[buf.length - 1];
		ByteArrayInputStream byteStream = new ByteArrayInputStream(buf);
		DataInputStream dataStream = new DataInputStream(byteStream);

		 try {
			Obj_type = dataStream.readByte() & 255;
			dataStream.readFully(obj_buf, 0, obj_buf.length);
		} catch(java.io.IOException e) {
			System.out.println("IOException in reading Obj_type: " + e);
		}

		switch (Obj_type) {
		case ObjType.LINE:
			Line wbLine = new Line(this);
			wbLine.processInData(obj_buf);
			break;
		case ObjType.RECT:
			Rect wbRect = new Rect(this);
			wbRect.processInData(obj_buf);
			break;
		case ObjType.CIRCLE:
			Circle wbCircle = new Circle(this);
			wbCircle.processInData(obj_buf);
			break;
		case ObjType.OVAL:
			Oval wbOval = new Oval(this);
			wbOval.processInData(obj_buf);
			break;
		case ObjType.TEXT:
			Text wbText = new Text(this);
			wbText.processInData(obj_buf);
			break;
		case ObjType.IMAGE:
			Img wbImage = new Img(this);
			wbImage.processInData(obj_buf);
			break;
		case ObjType.DELETE:
			proc_obj(obj_buf, ObjType.DELETE);
			break;
		case ObjType.MOVE:
			proc_obj(obj_buf, ObjType.MOVE);
			break;
		default:
			System.out.println("No matching Obj_type !!!");
		}
	}

	/** dispatches object to either the method to move or delete the object,
	  * based on the requestType. The requestType is either a MOVE or 
	  * DELETE request.
	  * @param obj_buf buffer holding the object ID and object parameters
	  * @param requestType a MOVE or DELETE request
	  **/

	public void proc_obj(byte[] obj_buf, int requestType) {
		ByteArrayInputStream byteStream = new ByteArrayInputStream(obj_buf);
		DataInputStream dataStream = new DataInputStream(byteStream);
		byte[] buf = new byte[1024];
		int obj_id = 0;

		 try {
			obj_id = dataStream.readInt();

			if ( requestType == ObjType.MOVE ) {
				dataStream.readFully(buf, 0, buf.length);
			}

		} catch(java.io.IOException e) {
			System.out.println("IOException in readInt for obj_id : " + e);
		}

		if (requestType == ObjType.MOVE)
			update_moved_obj(obj_id, buf);
		else if (requestType == ObjType.DELETE)
			erase_recvd_obj(obj_id);
	}

	/** Updates the object whenever this object has been moved remotely.
      * Function will search through the stack again for every movement 
	  * of the remote object if and only if this object wasn't previously
	  * moved object. Otherwise, it will not need to search the whole
	  * stack, thus improving response time.
	  * @param obj_id object ID of the object to be updated.
	  * @param buf buffer holding the object parameters.
	  **/

	public void update_moved_obj(int obj_id, byte[] buf) {
		ByteArrayInputStream byteStream = new ByteArrayInputStream(buf);
		DataInputStream dataStream = new DataInputStream(byteStream);
		DrawObject top;
		boolean found = false;
		int popped_obj_id = 0;
		int popcount = 0;
		boolean search_stack = false;

		if (objToMove == null) {
			 search_stack = true;
		}
		else {
			if (objToMove.getObjID() == obj_id) {
				moveObj(objToMove, dataStream);
			} else
				 search_stack = true;
		}

		while (!found && !S1.empty() && search_stack) {
			popcount++;

			top = (DrawObject) S1.pop();
			popped_obj_id = top.getObjID();
			Graphics g = getGraphics();

			if (popped_obj_id == obj_id) {
				moveObj(top, dataStream);
				found = true;
			}
			S2.push(top);
		}

		if (search_stack) {
			while (popcount-- > 0)
				S1.push(S2.pop());
			search_stack = false;
		}
	}

	public void moveObj(DrawObject top, DataInputStream dataStream) {

		if (top instanceof Line) {
			Line line = (Line) top;
			line.erase(offscreenG, false);
			update_obj_params((Object) line, dataStream, offscreenG);
			objToMove = (DrawObject) line;

		} else if (top instanceof Rect) {
			Rect rect = (Rect) top;
			rect.erase(offscreenG, false);
			update_obj_params((Object) rect, dataStream, offscreenG);
			objToMove = (DrawObject) rect;

		} else if (top instanceof Oval) {
			Oval oval = (Oval) top;
			oval.erase(offscreenG, false);
			update_obj_params((Object) oval, dataStream, offscreenG);
			objToMove = (DrawObject) oval;

		} else if (top instanceof Circle) {
			Circle circle = (Circle) top;
			circle.erase(offscreenG, false);
			update_obj_params((Object) circle, dataStream, offscreenG);
			objToMove = (DrawObject) circle;

		} else if (top instanceof Text) {
			Text textobj = (Text) top;
			textobj.erase(offscreenG, false);
			update_obj_params((Object) textobj, dataStream, offscreenG);
			objToMove = (DrawObject) textobj;

		} else if (top instanceof Img) {
			Img imageobj = (Img) top;
			imageobj.erase(offscreenG, false);
			update_obj_params((Object) imageobj, dataStream, offscreenG);
			objToMove = (DrawObject) imageobj;
		}
		
	}

	public void update_obj_params(Object ObjectType, DataInputStream dataStream,
				       Graphics offscreenG) {
		int param1 = 0;
		int param2 = 0;
		int param3 = 0;
		int param4 = 0;

		 try {
			dataStream.readByte();
			param1 = dataStream.readUnsignedShort();
			param2 = dataStream.readUnsignedShort();
			param3 = dataStream.readUnsignedShort();
			param4 = dataStream.readUnsignedShort();
		} catch(java.io.IOException e) {
			System.out.println("IOException in readUnsignedShort in update_obj_params:"+e);
		}

		if (ObjectType instanceof Line) {
			Line line = (Line) ObjectType;
			line.x1 = param1;
			line.y1 = param2;
			line.x2 = param3;
			line.y2 = param4;
			line.paint(offscreenG);

		} else if (ObjectType instanceof Rect) {
			Rect rect = (Rect) ObjectType;
			rect.x1 = param1;
			rect.y1 = param2;
			rect.width = param3;
			rect.height = param4;
			rect.paint(offscreenG);

		} else if (ObjectType instanceof Oval) {
			Oval oval = (Oval) ObjectType;
			oval.x1 = param1;
			oval.y1 = param2;
			oval.width = param3;
			oval.height = param4;
			oval.paint(offscreenG);

		} else if (ObjectType instanceof Circle) {
			Circle circle = (Circle) ObjectType;
			circle.x1 = param1;
			circle.y1 = param2;
			circle.width = param3;
			circle.height = param4;
			circle.paint(offscreenG);

		} else if (ObjectType instanceof Text) {
			Text textobj = (Text) ObjectType;
			textobj.x1 = param1;
			textobj.y1 = param2;
			textobj.width = param3;
			textobj.height = param4;
			textobj.paint(offscreenG);

		} else if (ObjectType instanceof Img) {
			Img imageobj = (Img) ObjectType;
			imageobj.x1 = param1;
			imageobj.y1 = param2;
			imageobj.imageWidth = param3;
			imageobj.imageHeight = param4;
			imageobj.paint(offscreenG);
		}
		repaint();
	}

	/** processes objects to be erased whenever a remote DELETE request
	  * is received. Function reads the object ID of received object before
	  * calling erase_recvd_obj to erase this object.
	  * @param obj_buf buffer containing incoming object parameters and object
	  * ID.
	  * @return void
	  **/

	/*public void proc_del_obj(byte[] obj_buf) {
		ByteArrayInputStream byteStream = new ByteArrayInputStream(obj_buf);
		DataInputStream dataStream = new DataInputStream(byteStream);

		 try {
			erase_recvd_obj(dataStream.readInt());
		} catch(java.io.IOException e) {
			System.out.println("IOException in readInt for obj_id : " + e);
		}
	}
	*/


	/** searches through the stack to find the correct object to be deleted
	  * following the remote DELETE request. Called by proc_del_obj function
	  * that passes to it the object ID to identify the object to be deleted.
	  * @param obj_id object ID to identify the object from the stack to be
	  * deleted.
	  * @return void
	  **/

	public void erase_recvd_obj(int obj_id) {
		DrawObject top;
		boolean found = false;
		int popped_obj_id = 0;
		int popcount = 0;

		while (!found && !S1.empty()) {
			popcount++;

			top = (DrawObject) S1.pop();
			popped_obj_id = top.getObjID();

			if (popped_obj_id == obj_id) {
				if (top instanceof Line) {
					Line line = (Line) top;
					 line.erase(offscreenG, false);
				} else if (top instanceof Rect) {
					Rect rect = (Rect) top;
					rect.erase(offscreenG, false);
				} else if (top instanceof Oval) {
					Oval oval = (Oval) top;
					oval.erase(offscreenG, false);
				} else if (top instanceof Circle) {
					Circle circle = (Circle) top;
					circle.erase(offscreenG, false);
				} else if (top instanceof Text) {
					Text textobj = (Text) top;
					textobj.erase(offscreenG, false);
				} else if (top instanceof Img) {
					Img imageobj = (Img) top;
					imageobj.erase(offscreenG, false);
				}

				repaint();
				popcount--;
				found = true;
			} else
				S2.push(top);
		}

		while (popcount-- > 0)
			S1.push(S2.pop());
	}


	/**
	 * add one object to the stack
	 *
	 *@param theObj object reference
	 *@return void
	 */

	public void addStack(Object theObj) {
		S1.push(theObj);
	}

}

class TextEntryDlg extends Frame {
	SketchArea parent;
	TextField textfield = new TextField(10);
	int x, y, color;

	public TextEntryDlg(SketchArea parent, int x, int y, int color) {
		super("Enter String");
		this.parent = parent;
		this.x = x;
		this.y = y;
		this.color = color;
		setLayout(new FlowLayout());
		add(textfield);
		add(new Button("OK"));

		resize(200, 100);
	}

	/*public boolean handleEvent(Event e) {
		switch(e.id) {
			case Event.ACTION_EVENT:
				if (e.target instanceof Button) {
					String label = ((Button)e.target).getLabel();
					if (label.equals("OK")) {
						text = textfield.getText();
						this.removeAll();
						this.hide();
					}
				return true;
				break;
			}
		}
	}
	*/

	public boolean action(Event e, Object what) {
		if (e.arg.equals("OK")) {
						parent.proctextfield(x, y, color, textfield.getText());
						this.removeAll();
						this.hide();
		}
		return true;
	}
}

