package eu.dnetlib.client;

import java.util.ArrayList;
import java.util.logging.Logger;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.sencha.gxt.widget.core.client.Dialog.PredefinedButton;
import com.sencha.gxt.widget.core.client.box.MessageBox;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.event.HideEvent;
import com.sencha.gxt.widget.core.client.event.HideEvent.HideHandler;

import eu.dnetlib.client.loader.ComponentLoader;
import eu.dnetlib.client.loader.ReloadListenerAdapter;
import eu.dnetlib.client.managers.ActiveComponentsManager;
import eu.dnetlib.client.managers.NotificationManager;
import eu.dnetlib.client.managers.PermissionsManager;
import eu.dnetlib.client.parsingUtils.EfgConstants;
import eu.dnetlib.client.resources.frame.Frames;
import eu.dnetlib.client.resources.item.Items;
import eu.dnetlib.client.resources.systemconfigration.SystemConfiguration;
import eu.dnetlib.client.resources.theme.Themes;
import eu.dnetlib.client.resources.topic.Topics;
import eu.dnetlib.client.resources.usermanagement.UserLogin;
import eu.dnetlib.client.resources.usermanagement.Users;
import eu.dnetlib.client.shared.MainMenuBar;
import eu.dnetlib.client.shared.MainMenuBar.MenuPage;
import eu.dnetlib.efg1914.authoring.components.MD5;
import eu.dnetlib.efg1914.authoring.users.User;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class EFG1914AuthoringGui implements EntryPoint {
	/**
	 * This is the entry point method. //
	 */
	private static Logger rootLogger = Logger.getLogger("efgauth.java");
	private VerticalPanel resourcePanel = new VerticalPanel();
	private NotificationManager notificationManager;
	private PermissionsManager permissionsManager;
	private HorizontalPanel menuPanel = new HorizontalPanel();
	private LoginServiceAsync loginservice = GWT.create(eu.dnetlib.client.LoginService.class);
	private Items items;
	private Frames frames;
	private Topics topics;
	private Themes themes;
	private Users users;
	SystemConfiguration systemConfiguration;
	/* Logic for GWTEventService ends here */
	private MainMenuBar menu;
	private UserLogin login = new UserLogin();
	private User currentUser;
	private EfgConstants efgConstants = GWT.create(EfgConstants.class);
	final Image menuImage = new Image(this.efgConstants.firstPageImage());
	private FlowPanel titleAndLogin = new FlowPanel();
	private ComponentLoader componentLoader;
	private String sessionId;
	private ActiveComponentsManager activeManager = GinWidgetGinjector.INSTANCE.getActiveComponentsManager();
	private int tries = 0;

	public EFG1914AuthoringGui() {
		
		rootLogger.info("adding window closing handler");

		titleAndLogin.setVisible(false);
		RootPanel.get("logout").setVisible(false);

		Window.addCloseHandler(new CloseHandler<Window>() {

			public void onClose(CloseEvent<Window> event) {
				rootLogger.info("CLOOOOOOOOOOOOOOOOOSING");
				if (componentLoader != null) {
					// TODO kill loading thread here
					componentLoader.stop();

				}
				// TODO tke it to the right place
				for (String componentsId : componentLoader.getStartupComponents().getMyLockedComponentList()) {
					activeManager.unMarkItem(componentsId, componentLoader.getStartupComponents().getUser().getId());

				}
				// TODO : edo einai to reload :)

				notificationManager.unregisterUser(currentUser.getId(), componentLoader.getStartupComponents().getMyLockedComponentList());

				// TODO add here services for cleaning cache-sessions-e

				removeUnsavedUploads();

			}
		});
		menu = new MainMenuBar(resourcePanel);

		menuPanel.add(menu.getMenu());
		rootLogger.info("adding change history value handler");

		History.addValueChangeHandler(new ValueChangeHandler<String>() {
			public void onValueChange(ValueChangeEvent<String> event) {
				rootLogger.info("on value Changed Handler!!!");
				String historyToken = event.getValue();
				// Parse the history token
				menu.parseHistoryToken(historyToken);

			}
		});
		Image efg1914 = new Image(efgConstants.firstPageImage());
		efg1914.setStyleName("firstPageImage");
		titleAndLogin.add(efg1914);

		final HTML firstPageTitle = new HTML("<h1>" + efgConstants.firstPageTitle() + "</h1>");

		firstPageTitle.setStyleName("firstPageTitle center");

		titleAndLogin.add(firstPageTitle);
		titleAndLogin.add(login.getLoginPanel());

		login.getLoginPanel().setStyleName("loginPanel center");

		RootPanel.get("logout").add(login.getLogoutPanel());
		titleAndLogin.setStyleName("titleAndLogin");
		RootPanel.get("titleAndLogin").add(titleAndLogin);

		Panel thePanel = createUI();
		RootPanel.get().add(thePanel);

		final Image loadingImage = new Image("images/loading.gif");

		RootPanel.get("loading").add(loadingImage);
		RootPanel.get("loading").setVisible(false);

		login.getLogIn().addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent arg0) {

				titleAndLogin.setVisible(false);
				RootPanel.get("loading").setVisible(true);
				login.getLogIn().setEnabled(false);

				String userName = login.getUserNameLogin().getText().toString();
				String pass = login.getPasswordLogin().getText();

				loginservice.login(userName, MD5.encrypt(pass), true, new AsyncCallback<String>() {

					public void onSuccess(String sessionId) {
						loginservice.getUser(new AsyncCallback<User>() {

							public void onSuccess(User u) {
								currentUser = u;

								loadComponents();

							}

							public void onFailure(Throwable arg0) {
								rootLogger.warning("login and user fetch failed");
							}

						});
						EFG1914AuthoringGui.this.sessionId = sessionId;
					}

					public void onFailure(Throwable arg0) {
						RootPanel.get("loading").setVisible(false);
						rootLogger.warning("user does not exist" + " " + login.getUserNameLogin().getText() + " " + login.getPasswordLogin().getText() + " " + arg0.getMessage() + " " + arg0.toString());
						showLogin();
						login.getLogInMessage().setText("Authentication Failed. Please try again.");
						login.getLogInMessage().setVisible(true);

						login.getLogIn().setEnabled(true);
					}
				});
			}
		});
		login.getLogoutButton().addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent arg0) {
				logoutAction(false);
			}
		});

 
	}

	public void logoutAction(boolean hasExpired) {
		// TODO tke it to the right place
		for (String componentsId : componentLoader.getStartupComponents().getMyLockedComponentList()) {
			activeManager.unMarkItem(componentsId, componentLoader.getStartupComponents().getUser().getId());

		}
		notificationManager.unregisterUser(currentUser.getId(), componentLoader.getStartupComponents().getMyLockedComponentList());
		// notificationManager.destroyCometServices();
		if (!hasExpired) {
			loginservice.logout(new AsyncCallback<Void>() {

				public void onSuccess(Void arg0) {
					rootLogger.info("....................LOGOUT SUCESSSFUL FOR USER FROM LOGOUT SERVICE...................");
					removeUnsavedUploads();
					componentLoader.stop();
				}

				public void onFailure(Throwable arg0) {
					rootLogger.warning("....................FAIL T LOGOUT FOR USER FROM LOGOUT SERVICE..................." + arg0);

				}
			});
		}
		showLogin();
		// Window.Location.replace("http://scoobydoo.di.uoa.gr/authoring/sessionExpired.html");
	}

	public void removeUnsavedUploads() {
		rootLogger.info(".............remove unsaved uploads..........................");
		rootLogger.info(" remove from theme");
 		themes.getThemesForm().cancelDiscardAction(false, false, null, null);
		rootLogger.info("remove from item");
 		items.getItemEditPanel().discardAndCancel(false,false,null, null);
	}

	public void onModuleLoad() {

		loginservice.checkLogin(new AsyncCallback<Boolean>() {

			public void onSuccess(Boolean isLoggedin) {
				if (isLoggedin) {
					loginservice.getUser(new AsyncCallback<User>() {

						public void onSuccess(User user) {

							currentUser = user;

							titleAndLogin.setVisible(false);
							RootPanel.get("loading").setVisible(true);

							reloadComponents();

						}

						public void onFailure(Throwable arg0) {
							rootLogger.warning("fail to get  user ");

							showLogin();
							login.getLogInMessage().setText("An error ocurred. Please login again.");
							login.getLogInMessage().setVisible(true);
						}
					});
				} else {
					rootLogger.warning("not logged in.... please log in ");

					showLogin();
				}

			}

			public void onFailure(Throwable arg0) {
				showLogin();
			}
		});

	}

	public void reloadComponents() {
		componentLoader = GinWidgetGinjector.INSTANCE.getComponentLoader();
		componentLoader.init();

		componentLoader.setUser(currentUser);
		loadListener = new MyReloadListenerAdapter();
		componentLoader.addReloadListener(loadListener);

	}

	public void loadComponents() {
		componentLoader = GinWidgetGinjector.INSTANCE.getComponentLoader();
		// TODO ERI!!!!!!!
		// check init --> reloadListenerAdapters.clear(); ( gi auto grafotan
		// polles fores sto notification!)
		componentLoader.init();
		componentLoader.setUser(currentUser);
		loadListener = new MyReloadListenerAdapter();
		componentLoader.addReloadListener(loadListener);

	}

	private Panel createUI() {
		FlowPanel thePanel = new FlowPanel();

		thePanel.setSize("60%", "60%");
		thePanel.setStyleName("borderPanel");

		return thePanel;
	}

	public void showLogin() {
		RootPanel.get("logout").setVisible(false);
		login.getSessionExpiredmessage().setVisible(false);
		menuPanel.setVisible(false);
		menuImage.setVisible(false);
		if (RootPanel.get("loading") != null && RootPanel.get("loading").isVisible()) {
			RootPanel.get("loading").setVisible(false);
		}
		titleAndLogin.setVisible(true);
		login.clearFields();
		resourcePanel.clear();
		Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
			public void execute() {
				login.getUserNameLogin().getElement().focus();
			}
		});

	}

	public void showLogout() {
		RootPanel.get("logout").setVisible(true);
		menuPanel.setVisible(true);
		menuImage.setVisible(true);
		login.getSessionExpiredmessage().setVisible(false);
		titleAndLogin.setVisible(false);
	}

	public void createPanels() {
		final Timer sessionTimeoutResponseTimer = new Timer() {
			@Override
			public void run() {

				final MessageBox cbOutdatedData = new MessageBox("Warning", "Session has expired. You might have outdated content. Please login again. <br>");
				cbOutdatedData.setPredefinedButtons(PredefinedButton.OK);
				cbOutdatedData.setIcon(MessageBox.ICONS.warning());
				cbOutdatedData.setMinHeight(100);
				cbOutdatedData.setMinWidth(350);

				cbOutdatedData.addHideHandler(new HideHandler() {

					public void onHide(HideEvent event) {

						logoutAction(true);
						login.getLogInMessage().setText("Session has expired. Please login again.");
						login.getLogInMessage().setVisible(true);

					}
				});
				cbOutdatedData.show();
			}
		};
		loginservice.getSessionMaxInterval(new AsyncCallback<Integer>() {

			public void onSuccess(Integer millis) {

				sessionTimeoutResponseTimer.schedule(millis - (1 * 1000));

			}

			public void onFailure(Throwable arg0) {
				sessionTimeoutResponseTimer.schedule(0);

			}
		});

		// keep those who need to load components first on list
		// TODO move loading of SC to a Init() and make sure that eveyting else
		// starts after they've been loaded
		tries = 0;
		componentLoader.getStartupComponents().setMyLockedComponentList(new ArrayList<String>());
		items = GinWidgetGinjector.INSTANCE.getItems();
		frames = GinWidgetGinjector.INSTANCE.getFrames();
		topics = GinWidgetGinjector.INSTANCE.getTopics();
		themes = GinWidgetGinjector.INSTANCE.getThemes();
		users = GinWidgetGinjector.INSTANCE.getUsers();

		items.init();
		frames.init();
		topics.init();
		themes.init();
		users.init();

		notificationManager = GinWidgetGinjector.INSTANCE.getNotificationManager();
		permissionsManager = GinWidgetGinjector.INSTANCE.getPermissionsManager();

		notificationManager.InitCometServices(currentUser.getId());

		resourcePanel.clear();
		resourcePanel.add(themes.getPanel());
		resourcePanel.add(topics.getPanel());
		resourcePanel.add(frames.getPanel());
		resourcePanel.add(items.getPanel());
		resourcePanel.getElement().getStyle().setWidth(100, Unit.PCT);
		resourcePanel.add(users.getPanel());

		rootLogger.info("History---FirstToken: " + History.getToken());

		menu.setSystemConfiguration(null);
		// permissionsManager.isPermitted(startUpComponents.getUser().getId(),
		// "mainpage", "edit")
		// if (permissionsManager.isPermitted(currentUser.getId(), "mainpage",
		// "edit") || permissionsManager.isPermitted(currentUser.getId(),
		// "system", "edit")) {
		if (permissionsManager.isPermitted(currentUser.getId(), "mainpage", "view")) {
			systemConfiguration = GinWidgetGinjector.INSTANCE.getSystemConfiguration();
			systemConfiguration.init();
			resourcePanel.add(systemConfiguration.getPanel());
			menu.setSystemConfiguration(systemConfiguration);

		} else {
			// Not permissions
			FlowPanel errorPageforSysConf = new FlowPanel();
			errorPageforSysConf.setStyleName("errorPage");
			errorPageforSysConf.add(new HTML("<span class=error404 >404</span><h2>Page not found<h2> "));
			resourcePanel.add(errorPageforSysConf);
		}

		FlowPanel errorPage = new FlowPanel();
		errorPage.setStyleName("errorPage");
		errorPage.add(new HTML("<span class=error404 >404</span><h2>Page not found<h2> "));
		resourcePanel.add(errorPage);

		menu.setItems(items);
		menu.setFrames(frames);
		menu.setTopics(topics);
		menu.setThemes(themes);
		menu.setUserManagement(users);

		items.setMainMenu(menu);
		frames.setMainMenu(menu);
		topics.setMainMenu(menu);
		themes.setMainMenu(menu);

		menuImage.setStyleName("menuImage");

		RootPanel.get("menuImage").add(menuImage);
		RootPanel.get("menuPanel").add(menuPanel);
		RootPanel.get("resourcesPanel").add(resourcePanel);

		// Hyperlink viewProfileButton = new Hyperlink("My Profile", "page=" +
		// MenuPage.USERS + "?id=myProfile");
		// viewProfileButton.setText("My Profile");
		// login.setViewProfileButton(viewProfileButton);

		String role = componentLoader.getStartupComponents().getUser().getRole();
		if (role.equals("Administrator") || role.equals("Theme Curator")) {
			menu.setDefaultMenuPage(MenuPage.THEME);
		} else if (role.equals("Topic Curator")) {
			menu.setDefaultMenuPage(MenuPage.TOPIC);
		} else if (role.equals("Curator")) {
			menu.setDefaultMenuPage(MenuPage.ITEMS);
		}
		// false -> don't show edit mode of a component---> maybe it's locked
		// and locked components may have not be updated yet....
		menu.parseHistoryToken(History.getToken(), false);

		// Button test= new Button("TEST");
		// RootPanel.get().add(test);
		// test.addClickHandler(new ClickHandler() {
		//
		// public void onClick(ClickEvent arg0) {
		// loginservice.isValid(new AsyncCallback<Boolean>() {
		//
		// public void onSuccess(Boolean arg0) {
		//
		// EFG1914AuthoringGui.this.rootLogger.info("test  -->  success!!   ******** is valid:"+arg0);
		// }
		//
		// public void onFailure(Throwable arg0) {
		// arg0.printStackTrace();
		// EFG1914AuthoringGui.this.rootLogger.info("test  -->  fails!!");
		// showLogin();
		// login.getLogInMessage().setText("AAAAAAAAAAAAAAAAAAAAAAn error ocurred. Please login again.");
		// login.getLogInMessage().setVisible(true);
		//
		// }
		// });
		//
		// }
		// });
	}

	public void addHistoryToken(String token) {
		History.newItem(token);
	}

	// TODO ERI!!!!!!
	// check this
	public class MyReloadListenerAdapter extends ReloadListenerAdapter {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private boolean showMessage = false;

		public void load() {
			// rootLogger.info("\n\n **** LOADING  on listener");
			// Info.display("LOADING ....", "LOADING  ");
			// rootLogger.info("loaded from componentLoader  " +
			// componentLoader.getStartupComponents().getUser().getUsername());
			// TODO create panels here
			createPanels();

			RootPanel.get("loading").setVisible(false);

			login.getLogInMessage().setText("Logged in");
			login.getLogInMessage().setVisible(true);
			login.getLogoutPanel().setVisible(true);
			// login.getLogoutMessage().setText("Welcome " +
			// currentUser.getUsername() + "!");
			login.getLogoutMessage().setText("Welcome ");
			login.getViewProfileButton().setText(currentUser.getUsername());

			showLogout();
		}

		public void reload() {

		}

		public void error(errorCodes errorCode) {

			rootLogger.warning("....................FAIL to load components...................\n ");
			if (errorCode.equals(errorCodes.FIRST_LOAD_ERROR)) {
				// if an error occurs the first time that components are being
				// loaded ( right after user login)

				rootLogger.warning("Please login again. ");
				if (tries > 10) {

					showLogin();
					login.getLogInMessage().setText("An error ocurred. Please login again.");
					login.getLogInMessage().setVisible(true);
				} else {
					onModuleLoad();
				}
				tries++;
			} else if (errorCode.equals(errorCodes.RELOAD_ERROR)) {

				// if an error occurs during periodic reloads
				rootLogger.warning("Failed to reload components from DB. Please mind that you might have outdated content.");
				rootLogger.warning("Please login again. ");
				tries++;
				if (tries > 0 && !showMessage && !titleAndLogin.isVisible()) {
					final MessageBox cbOutdatedData = new MessageBox("Warning", "Session has expired. You might have outdated content. Please login again. <br>");
					cbOutdatedData.setPredefinedButtons(PredefinedButton.YES, PredefinedButton.CANCEL);
					cbOutdatedData.setIcon(MessageBox.ICONS.warning());
					((TextButton) cbOutdatedData.getButtonBar().getWidget(0)).setText("Login again");
					cbOutdatedData.setMinHeight(100);
					cbOutdatedData.setMinWidth(350);

					cbOutdatedData.addHideHandler(new HideHandler() {

						public void onHide(HideEvent event) {
							String buttonText = cbOutdatedData.getHideButton().getText();
							if (buttonText.equals("Login again")) {
								logoutAction(true);
								login.getLogInMessage().setText("Session has expired. Please login again.");
								login.getLogInMessage().setVisible(true);
								showMessage = false;
							} else {
								// do nothing
								showMessage = false;
								login.getSessionExpiredmessage().setVisible(true);
							}
						}
					});
					cbOutdatedData.show();
					showMessage = true;
				}
			}

		}

	};

	private ReloadListenerAdapter loadListener = new MyReloadListenerAdapter();
	// private ReloadListenerAdapter loadListener = new ReloadListenerAdapter()
	// {
	//
	// /**
	// *
	// */
	// private static final long serialVersionUID = 1L;
	//
	// public void load() {
	// // rootLogger.info("\n\n **** LOADING  on listener");
	// // Info.display("LOADING ....", "LOADING  ");
	// // rootLogger.info("loaded from componentLoader  " +
	// // componentLoader.getStartupComponents().getUser().getUsername());
	// // TODO create panels here
	// createPanels();
	//
	// RootPanel.get("loading").setVisible(false);
	//
	// login.getLogInMessage().setText("Logged in");
	// login.getLogInMessage().setVisible(true);
	// login.getLogoutPanel().setVisible(true);
	// // login.getLogoutMessage().setText("Welcome " +
	// // currentUser.getUsername() + "!");
	// login.getLogoutMessage().setText("Welcome ");
	// login.getViewProfileButton().setText(currentUser.getUsername());
	//
	// showLogout();
	// }
	//
	// public void reload() {
	//
	// }
	//
	// public void error(errorCodes errorCode) {
	//
	// rootLogger.warning("....................FAIL to load components...................\n ");
	//
	// if (errorCode.equals(errorCodes.FIRST_LOAD_ERROR)) {
	// // if an error occurs the first time that components are being
	// // loaded ( right after user login)
	// rootLogger.warning("Please login again. ");
	// login.getLogInMessage().setText("An error ocurred. Please login again.");
	// login.getLogInMessage().setVisible(true);
	//
	// onModuleLoad();
	//
	// } else if (errorCode.equals(errorCodes.RELOAD_ERROR)) {
	//
	// // if an error occurs during periodic reloads
	// rootLogger.warning("Failed to reload components from DB. Please mind that you might have outdated content.");
	//
	// }
	// }
	//
	// };

}
