/*
 * Copyright (c) 2009 University of Durham, England
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'SynergySpace' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package synergynet.table.apps.mathpadapp.clientapp;

import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;


import com.jme.math.Vector3f;
import com.jme.renderer.Camera;

import synergynet.contentsystem.ContentSystem;
import synergynet.contentsystem.items.ContentItem;
import synergynet.contentsystem.items.ImageTextLabel;
import synergynet.contentsystem.items.listener.ItemListener;

import synergynet.services.ServiceManager;

import synergynet.services.exceptions.CouldNotStartServiceException;
import synergynet.services.exceptions.ServiceNotRunningException;
import synergynet.services.net.netservicediscovery.NetworkServiceDiscoveryService;
import synergynet.services.net.tablecomms.client.TableCommsApplicationListener;
import synergynet.services.net.tablecomms.client.TableCommsClientService;
import synergynet.table.SynergyNetAppUtils;
import synergynet.table.appregistry.ApplicationInfo;
import synergynet.table.appregistry.menucontrol.HoldTopRightExit;
import synergynet.table.apps.DefaultSynergyNetApp;
import synergynet.table.apps.mathpadapp.MathPadUtils;
import synergynet.table.apps.mathpadapp.controllerapp.MathPadController;
import synergynet.table.apps.mathpadapp.controllerapp.assignmentcontroller.AssignmentInfo;
import synergynet.table.apps.mathpadapp.mathtool.MathTool;
import synergynet.table.apps.mathpadapp.mathtool.MathToolInitSettings;
import synergynet.table.apps.mathpadapp.mathtool.MathTool.MathToolListener;
import synergynet.table.apps.mathpadapp.mathtool.MathTool.SeparatorState;
import synergynet.table.apps.mathpadapp.mathtool.MathTool.WritingState;
import synergynet.table.apps.mathpadapp.networkmanager.handlers.client.ClientMessageHandler;
import synergynet.table.apps.mathpadapp.networkmanager.managers.ClientManager;
import synergynet.table.apps.mathpadapp.networkmanager.messages.fromclient.fromuser.RegisterUserMessage;
import synergynet.table.apps.mathpadapp.networkmanager.messages.fromclient.fromuser.UnregisterUserMessage;
import synergynet.table.apps.mathpadapp.networkmanager.utils.UserIdentity;
import synergynet.table.apps.mathpadapp.util.MTMessageBox;
import synergynet.table.apps.mathpadapp.util.MTMessageBox.MessageListener;
import synergyspace.jme.sysutils.CameraUtility;

public class MathPadClient extends DefaultSynergyNetApp{

	private TableCommsClientService comms = null;
	protected ClientMessageHandler messageHandler;
	protected ClientManager clientManager;
	private ContentSystem contentSystem;
	private NetworkServiceDiscoveryService nsds = null;
	
	protected int MAX_NUMBER_OF_PADS = 20;
	protected int currentNoOfPads = 0;
	
	public MathPadClient(ApplicationInfo info) {
		super(info);		
	}

	@Override
	public void addContent() {
		
		contentSystem = ContentSystem.getContentSystemForSynergyNetApp(this);		
		setMenuController(new HoldTopRightExit());
		SynergyNetAppUtils.addTableOverlay(this);

		ImageTextLabel btn = (ImageTextLabel) contentSystem.createContentItem(ImageTextLabel.class);
		btn.setAutoFitSize(false);
		btn.setWidth(80);
		btn.setHeight(80);
		btn.setBorderColour(Color.red);
		btn.setBackgroundColour(Color.white);
		btn.setImageInfo(MathPadUtils.class.getResource("images/controlbar/Math Pad.jpg"));
		btn.setCRLFSeparatedString("Math Pad");
		btn.setLocalLocation(50, 50);
		btn.setRotateTranslateScalable(false);
		
		
//		setAllContentSteadfast();
		
		btn.addItemListener(new ItemListener(){
			@Override
			public void cursorChanged(ContentItem item, long id, float x,
					float y, float pressure) {}

			@Override
			public void cursorClicked(ContentItem item, long id, float x,
					float y, float pressure) {
				if(currentNoOfPads == MAX_NUMBER_OF_PADS) return;
				final MathTool tool = new MathTool(contentSystem);
				currentNoOfPads++;
				MathToolInitSettings settings = new MathToolInitSettings();
				settings.setTextColor(Color.black);
				settings.setLineWidth(1.0f);
				settings.setSeparatorState(SeparatorState.COLLAPSED);
				settings.setWritingState(WritingState.FREE_DRAW);
				settings.setBackgroundColor(Color.white);
				settings.setLocationX(300);
				settings.setLocationY(300);
				settings.setOrder(4);
				settings.setScale(0.7f);
				tool.init(settings);
				tool.addMathToolListener(new MathToolListener(){

					@Override
					public void assignmentAnswerReady(AssignmentInfo info) {}

					@Override
					public void mathPadClosed(MathTool mathTool) {
						if(currentNoOfPads >0) currentNoOfPads--;
						if(clientManager == null) return;
						UserIdentity userId = clientManager.getUserIdentityForMathTool(mathTool);
						if(userId != null){
							UnregisterUserMessage message = new UnregisterUserMessage(MathPadController.class, userId);
							clientManager.sendMessage(message);
							clientManager.unregisterMathPad(userId);
						}
					}

					@Override
					public void separatorChanged(SeparatorState newState) {	}

					@Override
					public void userLogin(String userName, String password) {
						MathPadClient.this.login(tool, userName, password);
					}
					
				});
				
				// login with a random Name
				MathPadClient.this.login(tool, UUID.randomUUID().toString(), " ");
			}

			@Override
			public void cursorDoubleClicked(ContentItem item, long id, float x,	float y, float pressure) {}

			@Override
			public void cursorLongHeld(ContentItem item, long id, float x,	float y, float pressure) {}

			@Override
			public void cursorPressed(ContentItem item, long id, float x,float y, float pressure) {	}

			@Override
			public void cursorReleased(ContentItem item, long id, float x,float y, float pressure) {}

			@Override
			public void cursorRightClicked(ContentItem item, long id, float x,float y, float pressure) {}
			
		});
	}
	
	public void login(MathTool tool, String userName, String password){
		UserIdentity userId = new UserIdentity();
		userId.setUserIdentity(userName);
		userId.setPassword(password);
		if(clientManager != null){
			if(!clientManager.getRegisteredMathPads().containsValue(tool)){
				RegisterUserMessage message = new RegisterUserMessage(MathPadController.class, userId);
				clientManager.sendMessage(message);
				clientManager.registerMathPad(userId, tool);
			}else{
				final MTMessageBox msg = new MTMessageBox(tool,contentSystem);
				msg.setTitle("Login Error");
				msg.setMessage("You already logged in.");
				msg.getCancelButton().setVisible(false);
				msg.getOkButton().setLocalLocation(0, msg.getOkButton().getLocalLocation().y);
				msg.addMessageListener(new MessageListener(){
					@Override
					public void buttonClicked(String buttonId) {
					}

					@Override
					public void buttonReleased(String buttonId) {
						msg.close();
					}
				});
			}
		}
		tool.setTitle(userId.getUserIdentity());
	}
	
	@Override
	public void onActivate() {
		this.connect(true);
	}
	
	@Override
	protected void onDeactivate() {
	}

	protected Camera getCamera() {
		if(cam == null) {
			cam = CameraUtility.getCamera();
			cam.setLocation(new Vector3f(0f, 10f, 50f));
			cam.lookAt(new Vector3f(), new Vector3f( 0, 0, -1 ));
			cam.update();
		}		
		return cam;
	}

	@Override
	protected void stateUpdate(float tpf) {
		super.stateUpdate(tpf);
		if(contentSystem != null) contentSystem.update(tpf);
		if(clientManager != null) clientManager.update(tpf);
	}

	public void connect(final boolean isReconnect){
		
		new Thread(new Runnable(){
			@Override
			public void run(){
				try {
					if(comms == null) comms = (TableCommsClientService) ServiceManager.getInstance().get(TableCommsClientService.class);
					if(comms != null){
							while(!comms.isClientConnected()){
							Thread.sleep(1000);
							if(nsds == null){
								nsds = (NetworkServiceDiscoveryService) ServiceManager.getInstance().get(NetworkServiceDiscoveryService.class);
							}else{
								nsds.shutdown();
							}
							nsds.start();
							comms.start();
						}
						if(nsds != null) nsds.shutdown();

						ArrayList<Class<?>> receiverClasses = new ArrayList<Class<?>>();
						receiverClasses.add(MathPadController.class);
						HashMap<UserIdentity, MathTool> existingTools = null;
						if(isReconnect && clientManager != null) existingTools = clientManager.getRegisteredMathPads();
						clientManager = new ClientManager(contentSystem, comms, receiverClasses);
						messageHandler = new ClientMessageHandler(clientManager);
						comms.register(MathPadClient.this, messageHandler);
						if(isReconnect && existingTools != null){
							for(UserIdentity userId: existingTools.keySet()){
								RegisterUserMessage message = new RegisterUserMessage(MathPadController.class, userId);
								clientManager.sendMessage(message);
								clientManager.registerMathPad(userId, existingTools.get(userId));									
							}
						}
						comms.register("connection_listener", new TableCommsApplicationListener(){
							@Override
							public void messageReceived(Object obj) {
								// TODO Auto-generated method stub
								
							}

							@Override
							public void tableDisconnected() {
								if(comms != null)
									try {
										comms.stop();
									} catch (ServiceNotRunningException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
								comms = null;
								connect(true);
							}
							
						});
					}
				} catch (CouldNotStartServiceException e1) {
					e1.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}).start();
	}
	
}

