/*
 * Copyright (c) 2016 NECTEC
 *   National Electronics and Computer Technology Center, Thailand
 *
 * 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 th.or.nectec.marlo;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.maps.android.PolyUtil;
import th.or.nectec.marlo.model.PolygonData;

import java.util.List;
import java.util.Stack;

public class PolygonMarloFragment extends MarloFragment {

    private final Stack<PolygonData> multiPolygon = new Stack<>();
    private final PolygonData singlePolygon = new PolygonData();

    private State drawingState = State.BOUNDARY;
    private Mode mode = Mode.SINGLE;
    private PolygonFactory polygonFactory;

    public PolygonMarloFragment() {
        super();
        this.markerFactory = new DefaultPolygonMarkerFactory();
        this.polygonFactory = new DefaultPolygonFactory();
    }

    public static PolygonMarloFragment newInstance(Mode mode) {
        PolygonMarloFragment fragment = new PolygonMarloFragment();
        fragment.mode = mode;
        return fragment;
    }

    public void setMode(Mode mode) {
        this.mode = mode;
    }

    public void setPolygonFactory(PolygonFactory polygonFactory) {
        this.polygonFactory = polygonFactory;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        ViewUtils.addPolygonToolsMenu(this);
        findViewBy(R.id.marlo_boundary).setVisibility(mode == Mode.MULTI ? View.VISIBLE : View.GONE);
        multiPolygon.push(new PolygonData());
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.marlo_hole) {
            getActivePolygonData().getHoles().push(new Stack<Marker>());
            changeToHoleState();
        } else if (view.getId() == R.id.marlo_boundary) {
            multiPolygon.push(new PolygonData());
            changeToBoundary();
        } else if (view.getId() == R.id.marlo_undo) {
            undo();
        } else {
            super.onClick(view);
        }
    }

    private void changeToHoleState() {
        drawingState = State.HOLE;
    }

    private void changeToBoundary() {
        drawingState = State.BOUNDARY;
    }

    public PolygonData getActivePolygonData() {
        return mode == Mode.SINGLE ? singlePolygon : multiPolygon.peek();
    }

    @Override
    protected void onViewfinderClick(LatLng target) {
        SoundUtility.play(getContext(), R.raw.thumpsoundeffect);

        Marker marker = getGoogleMap().addMarker(markerFactory.build(this, target));
        switch (drawingState) {
            case BOUNDARY:
                getActivePolygonData().getBoundary().push(marker);
                break;
            case HOLE:
                Stack<Marker> lastHoles = getActivePolygonData().getHoles().peek();
                List<LatLng> pointsOfActivePolygon = getActivePolygonData().getPolygon().getPoints();
                boolean inBoundary = PolyUtil.containsLocation(target, pointsOfActivePolygon, false);
                if (inBoundary) {
                    lastHoles.push(marker);
                } else {
                    onMarkHoleOutBound(target, getActivePolygonData().getPolygon().getPoints());
                    marker.remove();
                }
                break;
        }
        PolygonDrawUtils.createPolygon(getGoogleMap(), getActivePolygonData(), polygonFactory.build(this));
    }

    private void onMarkHoleOutBound(LatLng target, List<LatLng> points) {
        Toast.makeText(getActivity(), "Out of polygon boundary", Toast.LENGTH_SHORT).show();
    }

    public void undo() {
        Stack<Stack<Marker>> holeMarker = getActivePolygonData().getHoles();
        if (!holeMarker.isEmpty()) {
            Stack<Marker> lastHoles = holeMarker.peek();
            if (!lastHoles.isEmpty()) {
                lastHoles.pop().remove();
            }
            if (lastHoles.isEmpty()) {
                holeMarker.pop();
            }
        } else {
            Stack<Marker> boundary = getActivePolygonData().getBoundary();
            if (!boundary.isEmpty()) {
                changeToBoundary();
                boundary.peek().remove();
                boundary.pop();
            }

            if (boundary.isEmpty() && mode == Mode.MULTI && multiPolygon.size() > 1) {
                multiPolygon.pop();
            }
        }
        PolygonDrawUtils.createPolygon(getGoogleMap(), getActivePolygonData(), polygonFactory.build(this));
    }

    public State getDrawingState() {
        return drawingState;
    }

    public Stack<PolygonData> getPolygons() {
        return multiPolygon;
    }

    public PolygonData getPolygon() {
        return singlePolygon;
    }

    public enum State {
        BOUNDARY,
        HOLE,
    }

    public enum Mode {
        SINGLE,
        MULTI
    }
}

@@ -3211,24 +3211,84 @@
 , target));%0A
+        PolygonData activePolygon = getActivePolygonData();%0A
         swit
@@ -3342,36 +3342,33 @@
                 
-getA
+a
 ctivePolygonData
@@ -3355,38 +3355,32 @@
    activePolygon
-Data()
 .getBoundary().p
@@ -3446,32 +3446,38 @@
                 
+Stack%3C
 Stack%3CMarker%3E la
@@ -3477,25 +3477,19 @@
 ker%3E
- lastH
+%3E h
 oles = 
-getA
+a
 ctiv
@@ -3488,38 +3488,32 @@
  = activePolygon
-Data()
 .getHoles().peek
@@ -3507,16 +3507,175 @@
 tHoles()
+;%0A                if (holes.isEmpty()) %7B%0A                    holes.push(new Stack%3CMarker%3E());%0A                %7D%0A                Stack%3CMarker%3E lastHoles = holes
 .peek();
@@ -3720,36 +3720,33 @@
 ActivePolygon = 
-getA
+a
 ctivePolygonData
@@ -3733,38 +3733,32 @@
  = activePolygon
-Data()
 .getPolygon().ge
@@ -4020,20 +4020,17 @@
 target, 
-getA
+a
 ctivePol
@@ -4029,30 +4029,24 @@
 ctivePolygon
-Data()
 .getPolygon(
@@ -4196,36 +4196,33 @@
 getGoogleMap(), 
-getA
+a
 ctivePolygonData
@@ -4209,38 +4209,32 @@
 ), activePolygon
-Data()
 , polygonFactory
@@ -4257,29 +4257,31 @@
    %7D%0A%0A    pr
-ivate
+otected
  void onMark
@@ -4393,16 +4393,17 @@
 boundary
+ 
 %22, Toast

fix bug when undo till hole is empty then mark new holes