package org.tizen.gwt.sample.raphaelpaint.client;

import org.tizen.gwt.sample.raphaelpaint.client.Enums.Operation;
import org.tizen.gwt.sample.raphaelpaint.client.Enums.Tool;
import org.tizen.gwt.sample.raphaelpaint.client.ShapeDrawer.Props;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.RaphaelAttr;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.BoundingClientRect;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.JQueryEvent;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.JQueryHandler;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.JsBag;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.RaphaelElement;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.TizenApplication;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.RaphaelElement.BBox;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.Raphael;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.JQuery;
import org.tizen.gwt.sample.raphaelpaint.client.overlay.JQuery.Css;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.user.client.Window;

import static org.tizen.gwt.sample.raphaelpaint.client.Msg.MSG;
import static org.tizen.gwt.sample.raphaelpaint.client.Constants.*;
import static com.google.gwt.user.client.DOM.*;

public class RaphaelPaint implements EntryPoint {

	protected Config mConfig;
	protected Transforms mTransforms;
	protected Raphael mPaper;
	protected Element mCanvasContainer;
	protected RaphaelElement mLastBox;
	protected RaphaelElement mSelectedShape;
	protected MyColorPicker mColorPicker;
	protected MyRotationSlider mRotationSlider;
	private ShapeDrawer mShapeDrawer;
	private JQuery mLabelFillColor;
	private JQuery mLabelStrokeColor;
	
	@Override
	public void onModuleLoad() {
		mConfig = new Config();
		mTransforms = new Transforms(this);
		mCanvasContainer = getElementById(ID_CANVAS_CONTAINER);
		mPaper = Raphael.create(mCanvasContainer, CANVAS_WIDTH, CANVAS_HEIGHT);
		mShapeDrawer = new ShapeDrawer(mPaper, mTransforms);
		mColorPicker = new MyColorPicker(this);
		mRotationSlider = new MyRotationSlider(this);
		initColorLabels();
		JQuery.jQuery(SELECTOR_BTN_CLOSE).on(JQueryEvent.CLICK, new JQueryHandler() {
			
			@Override
			public void onEvent(JQueryEvent event) {
				exit();
			}
		});
		JQuery.jQuery(mCanvasContainer).on(JQueryEvent.CLICK, new JQueryHandler() {
			
			@Override
			public void onEvent(JQueryEvent event) {
				event.preventDefault();
				double x = event.pageX(); 
				double y = event.pageY();
				RaphaelElement elem = null;
				switch (mConfig.mTool) {
					case arrow:
						elem = mPaper.getElementByPoint(x, y);
						if (elem == null) {
							if (mSelectedShape != null) {
								mSelectedShape = null;
								removeLastBox();
							}
						} else {
							setSelectedShape(elem);
						}
						break;
					case circle:
					case ellipse:
					case rectangle:
					case square:
					case star:
					case triangle:
						BoundingClientRect rect = BoundingClientRect.get(mCanvasContainer);
						paint(x - rect.getLeft(), y - rect.getTop());
						break;
					case eraser:
					case clear:
						break;
				}
			}
		});
		JQuery.jQuery(Operation.getElements()).on(JQueryEvent.CLICK, new JQueryHandler() {
			
			@Override
			public void onEvent(JQueryEvent event) {
				mConfig.mOperation = Operation.forElement(event.delegateTarget());
				switch(mConfig.mOperation) {
					case move:
					case scale:
						mRotationSlider.hide();
						break;
					case rotate:
						mRotationSlider.setRotation(mSelectedShape == null ?
								0 : mSelectedShape.<JsBag> cast().getInt(Props.ROTATION));
						mRotationSlider.show();
						break;
				}
			}
		});
		JQuery.jQuery(getElementById(ID_FILL_COLOR))
				.add(getElementById(ID_STROKE_COLOR))
				.on(JQueryEvent.CLICK, new JQueryHandler() {
				
			@Override
			public void onEvent(JQueryEvent event) {
				InputElement element = event.delegateTarget().cast();
				String id = element.getId();
				if (id.equals(mConfig.mColorOption)) {
					mConfig.mColorOption = null;
					mColorPicker.hide();
					element.setChecked(false);
				}
				else {
					if (mConfig.mColorOption == null) {
						mColorPicker.show();
					}
					mConfig.mColorOption = id;
					element.setChecked(true);
					updatePickerColor();
				}
			}
		});
		final JQuery arrowOperationsDiv = JQuery.jQuery(SELECTOR_ARROW_OPERATIONS_DIV);
		JQuery.jQuery(Tool.getElements()).on(JQueryEvent.CLICK, new JQueryHandler() {
			
			@Override
			public void onEvent(JQueryEvent event) {
				mConfig.mTool = Tool.forElement(event.delegateTarget());
				switch (mConfig.mTool) {
					case arrow:
						arrowOperationsDiv.show();
						break;
					case clear:
						arrowOperationsDiv.hide();
						mPaper.clear();
						removeLastBox();
						if (mSelectedShape != null) {
							mSelectedShape = null;
						}
						break;
					case circle:
					case ellipse:
					case eraser:
					case rectangle:
					case square:
					case star:
					case triangle:					
						arrowOperationsDiv.hide();
						break;
				}
			}
		});
	}
	
	public Tool getTool() {
		return mConfig.mTool;
	}
	
	public Operation getOperation() {
		return mConfig.mOperation;
	}
	
	public void addBox() {
		removeLastBox();
		BBox bBox = mSelectedShape.getBBox(false);
		mLastBox = mPaper.rect(bBox.getX(), bBox.getY(), bBox.getWidth(), 
				bBox.getHeight()).attr(RaphaelAttr.STROKE, COLOR_BOUNDING_BOX);
	}

	public void removeShape(RaphaelElement elem) {
		elem.remove();
		removeLastBox();
	}

	public void setSelectedShape(RaphaelElement elem) {
		mSelectedShape = elem; 
		addBox();
		mRotationSlider.setRotation(elem.<JsBag> cast().getInt(Props.ROTATION));
		setFillColorLabel(elem.attr(RaphaelAttr.FILL));
		setStrokeColorLabel(elem.attr(RaphaelAttr.STROKE));
		updatePickerColor();
	}
	
	protected void exit() {
		TizenApplication app = TizenApplication.getCurrentApplication();
		if (app == null) {
			Window.alert(MSG.notSupported());
		} else {
			if (Window.confirm(MSG.askIfExit())) {
				app.exit();
				TizenApplication.log(MSG.applicationClosed());
			}
		}
	}
	
	protected void onRotationChange(int rotation) {
		if (mSelectedShape != null) {
			mTransforms.setRotation(mSelectedShape, rotation);
		}
	}
	
	protected void onPickerClose() {
		mConfig.mColorOption = null;
		mColorPicker.hide();
	}
	
	protected void changeColor(String color) {
		if (ID_FILL_COLOR.equals(mConfig.mColorOption)) {
			setFillColorLabel(color);
			if (mSelectedShape != null) {
				mSelectedShape.attr(RaphaelAttr.FILL, color);
			}
		} 
		else if(ID_STROKE_COLOR.equals(mConfig.mColorOption)) {
			setStrokeColorLabel(color);
			if (mSelectedShape != null) {
				mSelectedShape.attr(RaphaelAttr.STROKE, color);
			}
		}
	}
	
	protected void paint (double x, double y) {
		RaphaelElement shape = mShapeDrawer.draw(mConfig.mTool, 
				mConfig.mFillColor, mConfig.mStrokeColor, x, y);
		if(shape != null) {
			setSelectedShape(shape);
		}
	}
	
	protected void updatePickerColor() {
		if(ID_FILL_COLOR.equals(mConfig.mColorOption)) {
			setPickerColor(mConfig.mFillColor);
		} 
		else if(ID_STROKE_COLOR.equals(mConfig.mColorOption)) { 
			setPickerColor(mConfig.mStrokeColor);
		}
	}
	
	private void removeLastBox() {
		if (mLastBox != null) {
			mLastBox.remove();
			mLastBox = null;
		}
	}
	
	private void setPickerColor(final String color) {
		mColorPicker.setColor(color);
	}

	private void initColorLabels() {
		mLabelFillColor = JQuery.jQuery(SELECTOR_LBL_CLR_FILL);
		refreshFillColorLabel();
		mLabelStrokeColor = JQuery.jQuery(SELECTOR_LBL_CLR_STROKE);
		refreshStrokeColorLabel();
	}
	
	private void setStrokeColorLabel(String color) {
		mConfig.mStrokeColor = color;
		refreshStrokeColorLabel();
	}

	private void setFillColorLabel(String color) {
		mConfig.mFillColor = color;
		refreshFillColorLabel();
	}
	
	private void refreshFillColorLabel() {
		mLabelFillColor.css(Css.BACKGROUND_COLOR, mConfig.mFillColor);
	}
	
	private void refreshStrokeColorLabel() {
		mLabelStrokeColor.css(Css.BACKGROUND_COLOR, mConfig.mStrokeColor);
	}
}