/**
 * Copyright 2011 The PlayN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package playn.html;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;

import playn.core.PlayN;
import playn.core.Touch;

class HtmlTouch extends HtmlInput implements Touch {
  private Listener listener;
  boolean inTouchSequence = false; // true when we are in a touch sequence (after touch start but before touch end)

  /**
   * Special implementation of Event.Impl for keeping track of changes to preventDefault
   */
  static class HtmlTouchEventImpl extends Event.Impl {
    final boolean[] preventDefault;

    public HtmlTouchEventImpl(double time, float x, float y, int id, boolean[] preventDefault) {
      super(time, x, y, id);
      this.preventDefault = preventDefault;
    }

    @Override
    public void setPreventDefault(boolean preventDefault) {
      this.preventDefault[0] = preventDefault;
    }

    @Override
    public boolean getPreventDefault() {
      return preventDefault[0];
    }
  }

  HtmlTouch(final Element rootElement) {
    // capture touch start on the root element, only.
    captureEvent(rootElement, "touchstart", new EventHandler() {
      @Override
      public void handleEvent(NativeEvent nativeEvent) {
        if (listener != null) {
          if (nativeEvent.getChangedTouches().length() != 0) {
            inTouchSequence = true;
            listener.onTouchStart(extrudeToucheEvents(nativeEvent,rootElement));
          } else {
            listener.onTouchStart(new Event[0]);
          }
        }
      }
    });

    // capture touch end anywhere on the page as long as we are in a touch sequence
    capturePageEvent("touchend", new EventHandler() {
      @Override
      public void handleEvent(NativeEvent nativeEvent) {
        if (listener != null && inTouchSequence) {
          listener.onTouchEnd(extrudeToucheEvents(nativeEvent,rootElement));
          // if there are no remaining active touches, note that this touch sequence has ended
          if (nativeEvent.getTouches().length() == 0)
            inTouchSequence = false;
        }
      }
    });

    // capture touch move anywhere on the page as long as we are in a touch sequence
    capturePageEvent("touchmove", new EventHandler() {
      @Override
      public void handleEvent(NativeEvent nativeEvent) {
        if (listener != null && inTouchSequence) {
          listener.onTouchMove(extrudeToucheEvents(nativeEvent,rootElement));
        }
      }
    });

    // capture touch move anywhere on the page as long as we are in a touch sequence
    capturePageEvent("touchcancel", new EventHandler() {
      @Override
      public void handleEvent(NativeEvent nativeEvent) {
        if (listener != null && inTouchSequence) {
          listener.onTouchCancel(extrudeToucheEvents(nativeEvent,rootElement));
        }
      }
    });
  }

  // extrude touche events from native event
  private Event[] extrudeToucheEvents(final NativeEvent fromNativeEvent, final Element rootElement) {
    JsArray<com.google.gwt.dom.client.Touch> nativeTouches = fromNativeEvent.getChangedTouches();
    int nativeTouchesLen = nativeTouches.length();

    boolean[] preventDefault = {false};

    // Convert the JsArray<Native Touch> to an array of Touch.Events
    Event[] touches = new Event[nativeTouchesLen];
    for (int t = 0; t < nativeTouchesLen; t++) {
      com.google.gwt.dom.client.Touch touch = nativeTouches.get(t);
      float x = touch.getRelativeX(rootElement);
      float y = touch.getRelativeY(rootElement);
      int id = getTouchIdentifier(fromNativeEvent, t);
      touches[t] = new HtmlTouchEventImpl(PlayN.currentTime(), x, y, id, preventDefault);
    }
    return touches;
  }

  @Override
  public void setListener(Listener listener) {
    this.listener = listener;
  }

  /**
   * Return the unique identifier of a touch, or 0
   *
   * @return return the unique identifier of a touch, or 0
   */
  private static native int getTouchIdentifier(NativeEvent evt, int index) /*-{
    return evt.changedTouches[index].identifier || 0;
  }-*/;
}

@@ -877,121 +877,163 @@
 ;%0A  
-boolean inT
+// keep our touch counter to check t
 ouch
-S
+ s
 equence
- = false; // true when we are in a touch sequence (after touch start but before touch end)
+. event.getTouches() don't given full info about current touches. May be gwt bug%0A  int currentTouches = 0;
 %0A%0A  
@@ -1958,44 +1958,8 @@
 ) %7B%0A
-            inTouchSequence = true;%0A
     
@@ -2027,32 +2027,98 @@
 ,rootElement));%0A
+            incTouches(nativeEvent.getChangedTouches().length());%0A
           %7D else
@@ -2444,32 +2444,34 @@
 ner != null && i
+sI
 nTouchSequence) 
@@ -2460,32 +2460,34 @@
 sInTouchSequence
+()
 ) %7B%0A          li
@@ -2565,106 +2565,18 @@
     
-// if there are no remaining active touches, note that this touch sequence has ended%0A          if 
+decTouches
 (nat
@@ -2579,32 +2579,39 @@
 (nativeEvent.get
+Changed
 Touches().length
@@ -2616,50 +2616,9 @@
 th()
- == 0)%0A            inTouchSequence = false
+)
 ;%0A  
@@ -2880,32 +2880,34 @@
 ner != null && i
+sI
 nTouchSequence) 
@@ -2896,32 +2896,34 @@
 sInTouchSequence
+()
 ) %7B%0A          li
@@ -3263,16 +3263,18 @@
 ull && i
+sI
 nTouchSe
@@ -3279,16 +3279,18 @@
 Sequence
+()
 ) %7B%0A    
@@ -3377,27 +3377,420 @@
     
-%7D%0A      %7D%0A    %7D);%0A 
+  decTouches(nativeEvent.getChangedTouches().length());%0A        %7D%0A      %7D%0A    %7D);%0A  %7D%0A%0A  // check if we have one or more current touches%0A  private boolean isInTouchSequence() %7B return currentTouches != 0; %7D%0A%0A  // increment touch counter%0A  private void incTouches(int on) %7B currentTouches += on; %7D%0A%0A  // decrement touch counter%0A  private void decTouches(int on) %7B currentTouches = Math.max(currentTouches - on,0);
  %7D%0A%0A

Fix problem with toucheSequence flag.