package org.ocpsoft.rewrite.gwt.client.history;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.google.gwt.user.client.impl.HistoryImpl;

/**
 * History implementation based on pushState
 */
public class HistoryStateImpl extends HistoryImpl
{
   private static List<ContextPathProvider> providers = Arrays.asList(new CookieContextPathProvider(),
            new RequestContextPathProvider());

   static String contextPath = null;

   private static List<ContextPathListener> listeners = new ArrayList<ContextPathListener>();

   @Override
   public boolean init()
   {
      for (ContextPathProvider provider : providers) {
         provider.getContextPath(this);
         if (contextPath != null)
         {
            break;
         }
      }

      return initNative();
   }

   static void setContextPath(String contextPath)
   {
      HistoryStateImpl.contextPath = contextPath;
      System.out.println("Set contextPath: " + contextPath);
      for (ContextPathListener listner : listeners) {
         listner.onContextPathSet(contextPath);
      }
   }

   public static ListenerRegistration addContextPathListener(final ContextPathListener listener)
   {
      listeners.add(listener);
      return new ListenerRegistration() {
         @Override
         public void removeListener()
         {
            listeners.remove(listener);
         }
      };
   }

   public static String getContextPath()
   {
      if (contextPath != null && !contextPath.endsWith("/"))
      {
         contextPath += "/";
      }
      return contextPath;
   }

   public static boolean isInitialized()
   {
      return contextPath != null;
   }

   public native boolean initNative() /*-{
		var token = '';
		var historyImpl = this;

		var path = $wnd.location.pathname;
		if (path.length > 0) {
			token = historyImpl.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(path);
			token = historyImpl.@HistoryStateImpl::cleanToken(Ljava/lang/String;)(token);
		}

		@com.google.gwt.user.client.impl.HistoryImpl::setToken(Ljava/lang/String;)(token);

		var oldHandler = $wnd.history.onpopstate;

		$wnd.onpopstate = $entry(function() {
			var token = '';
			var path = $wnd.location.pathname;
			if (path.length > 0) {
				token = historyImpl.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(path);
				token = historyImpl.@HistoryStateImpl::cleanToken(Ljava/lang/String;)(token);
			}

			historyImpl.@com.google.gwt.user.client.impl.HistoryImpl::newItemOnEvent(Ljava/lang/String;)(token);

			if (oldHandler) {
				oldHandler();
			}
		});

		return true;
   }-*/;

   protected String cleanToken(String historyToken)
   {
      String contextPath = HistoryStateImpl.getContextPath();
      if (!contextPath.equals(historyToken) && historyToken.startsWith(contextPath))
         historyToken = historyToken.substring(contextPath.length());

      System.out.println("History.pop() = [" + historyToken + "]");
      return historyToken;
   }

   @Override
   protected void nativeUpdate(String historyToken)
   {
      String contextPath = HistoryStateImpl.getContextPath();
      if (!contextPath.equals(historyToken))
         historyToken = contextPath + historyToken;

      System.out.println("History.push(" + historyToken + ")");
      update(historyToken);
   }

   protected native void update(String historyToken) /*-{
		var encodedToken = this.@com.google.gwt.user.client.impl.HistoryImpl::encodeFragment(Ljava/lang/String;)(historyToken);
		$wnd.history.pushState(encodedToken, $wnd.document.title, encodedToken);
   }-*/;

}
@@ -1954,32 +1954,71 @@
  = historyImpl.@
+org.ocpsoft.rewrite.gwt.client.history.
 HistoryStateImpl
@@ -2454,16 +2454,55 @@
 ryImpl.@
+org.ocpsoft.rewrite.gwt.client.history.
 HistoryS

fix migration bug