﻿/// <reference path="googlemaps-intellisense.js" />


function StreetViewController(pPanoDOMElement, pCancelledCallback, pShowFunction, pHideFunction) {

    //REGION Fields****************************************************************

    var me = this;
    this._client = new GStreetviewClient();

    //variables used to control the street view
    this._overlayInstance = null; //the blue street outline indicating street view
    this._markerGuy; //the marker guy
    this._lastMarkerLocation = null; //for keeping track of where the marker was before it was dragged, or somone clicked on the map, or moved by the pano
    this._panorama; //the actual panorama
    this._guyIcon = null;
    this._isFirstTimeViewed = true; //a flag inidicating this is the first time the street view control has been used
    this._panoDiv = pPanoDOMElement; //the div where the pano is to be created

    //Street view guy event handlers
    this._guyDragStartHandler = null;
    this._guyDraggingHandler = null;
    this._guyDragEndHandler = null;
    this._guyClickHandler = null;

    //Dom interaction
    this._showFunction = pShowFunction;
    this._hideFunction = pHideFunction;


    //Panoramic event handlers
    this._newPanoHandler = null; //fires when the user uses the arrows to move up and down a street in the pano
    this._yawChangedHandler = null; //fires when the user turns the pano view with the arrows
    this._panoErrorsHandler = null; //fires when the user does not have flash and other errors

    //External Callbacks
    this._streetViewCanceledCallback = pCancelledCallback;
    //END REGION Fields************************************************************




    //REGION: Lifetime*************************************************************
    this._InitializePanorama = function() {
        //create the pano
        me._panorama = new GStreetviewPanorama(me._panoDiv);

        //setup the icon
        me._guyIcon = me._CreateGuyIcon();


    }; //end InitializePanorama function

    this._CleanUP = function() {

        if (me._panorama) {
            me._RemoveGuyFromMap();
            if (me._overlayInstance != null) { map.removeOverlay(me._overlayInstance); };
            me._overlayInstance = null;

            //do the hide function if it exists
            if (me._hideFunction != null) { me._hideFunction(); };

            if (me._newPanoHandler != null) { GEvent.removeListener(me._newPanoHandler); };
            if (me._yawChangedHandler != null) { GEvent.removeListener(me._yawChangedHandler); };
            if (me._panoErrorsHandler != null) { GEvent.removeListener(me._panoErrorsHandler); };

            if (me._guyDragStartHandler != null) { GEvent.removeListener(me._guyDragStartHandler); };
            if (me._guyDraggingHandler != null) { GEvent.removeListener(me._guyDraggingHandler); };
            if (me._guyDragEndHandler != null) { GEvent.removeListener(me._guyDragEndHandler); };
            if (me._guyClickHandler != null) { GEvent.removeListener(me._guyClickHandler); };

            me._panorama.remove();

            //reaise cancel callback
            if (typeof me._streetViewCanceledCallback != "undefined" && me._streetViewCanceledCallback != null) {
                me._streetViewCanceledCallback();
            }; //end if cancel callback exists

        }; //end if StreetView
    };    //end CleanUP function
    //END REGION: Lifetime*********************************************************




    //REGION: External Entry Points************************************************
    this._ToggleStreetViewOverlay = function() {
        if (!me._overlayInstance) {
            //adding streetview
            me._overlayInstance = new GStreetviewOverlay();
            map.addOverlay(me._overlayInstance);

            //register for events
            me._newPanoHandler = GEvent.addListener(me._panorama, "initialized", me._OnNewLocation);
            me._yawChangedHandler = GEvent.addListener(me._panorama, "yawchanged", me._OnYawChange);
            me._panoErrorsHandler = GEvent.addListener(me._panorama, "error", me._HandlePanoErrors);

            me._DropGuyOnMap();
            me._panorama.checkResize();
        }
        else {
            //removing street view
            me._CleanUP();
        }; //end if/else overlay not null
    };  //end function



    this._MapClicked = function(pOverlay, pPoint) {
        me._markerGuy.setLatLng(pPoint);
        me._client.getNearestPanorama(pPoint, GISPlanning_MapUtilities_AssociateObjWithEvent(me, "_GetNearestPanoramaResponse"));
    }; //end function map clicked


    //END REGION: External Entry Points********************************************



    //REGION: Private Methods******************************************************

    this._DropGuyOnMap = function() {
        //set the position of the marker guy
        var myLatLng;
        if (me._lastMarkerLocation != null) {

            if (GISPlanning_MapUtilities_latLonInMapBounds(me._lastMarkerLocation.lat(), me._lastMarkerLocation.lng())) {
                myLatLng = me._lastMarkerLocation;
            }
            else {
                myLatLng = map.getCenter();
                me._lastMarkerLocation = myLatLng;
            };
        }
        else {
            myLatLng = map.getCenter();
        }; //end if else lastmarkerLocation not null

        //create and add the marker
        me._markerGuy = new GMarker(myLatLng, { icon: me._guyIcon, draggable: true });
        map.addOverlay(me._markerGuy);

        //add event handlers for marker
        me._guyClickHandler = GEvent.addListener(me._markerGuy, "click", me._ShowPanorama);
        me._guyDragStartHandler = GEvent.addListener(me._markerGuy, "dragstart", me._OnDragStart);
        me._guyDraggingHandler = GEvent.addListener(me._markerGuy, "drag", me._OnDragging);
        me._guyDragEndHandler = GEvent.addListener(me._markerGuy, "dragend", me._OnDragEnd);

        me._client.getNearestPanorama(myLatLng, GISPlanning_MapUtilities_AssociateObjWithEvent(me, "_GetNearestPanoramaResponse"));


    };      //end function


    this._RemoveGuyFromMap = function() {
        if (me._markerGuy != null) { map.removeOverlay(me._markerGuy); };
    }; //end function

    this._CreateGuyIcon = function() {
        var myGuyIcon = new GIcon(G_DEFAULT_ICON);
        myGuyIcon.image = "http://maps.google.com/intl/en_us/mapfiles/cb/man_arrow-0.png";
        myGuyIcon.transparent = "http://maps.google.com/intl/en_us/mapfiles/cb/man-pick.png";
        myGuyIcon.imageMap = [
        26, 13, 30, 14, 32, 28, 27, 28, 28, 36, 18, 35, 18, 27, 16, 26,
        16, 20, 16, 14, 19, 13, 22, 8
     ];
        myGuyIcon.iconSize = new GSize(49, 52);
        myGuyIcon.iconAnchor = new GPoint(25, 35);  // near base of guy's feet
        myGuyIcon.infoWindowAnchor = new GPoint(25, 5);  // top of guy's head

        return myGuyIcon;
    }; //end function

    this._ShowPanorama = function() {
        //set the latLng of the _panorama
        var myLatLng = me._markerGuy.getLatLng();
        me._panorama.setLocationAndPOV(myLatLng, null);

        //do the show function if it exists
        if (me._showFunction != null) { me._showFunction(); };

    };       //end function


    this._GetNearestPanoramaResponse = function(pResponse) {
        var myLatLng;
        if (pResponse.code != 200) {
            if (me._lastMarkerLocation != null) {
                myLatLng = me._lastMarkerLocation;
            }
            else {
                myLatLng = map.getCenter();
            }; //end if/else response not null
        }
        else {
            myLatLng = new GLatLng(pResponse.Location.lat, pResponse.Location.lng);
        }; //end if/else response not 200

        //set the last location
        me._lastMarkerLocation = myLatLng;

        me._markerGuy.setLatLng(me._lastMarkerLocation);

        //open the appropriate window
        if (me._isFirstTimeViewed || pResponse.code != 200) {
            me._isFirstTimeViewed = false;


            var myStreetViewInfoDiv = document.createElement("div");
            myStreetViewInfoDiv.innerHTML = "<p><b>Street View</b></p>";

            if (map.getZoom() < 13) {
                var myNeedZoomDiv = document.createElement("div");
                myNeedZoomDiv.appendChild(document.createTextNode("You need to zoom in to use Street View. "));

                var myZoomINLink = document.createElement("a");
                myZoomINLink.setAttribute("href", "#");
                myZoomINLink.appendChild(document.createTextNode("[Zoom In]"));
                $(myZoomINLink).click(function() { map.setZoom(13); map.closeInfoWindow(); });

                myNeedZoomDiv.appendChild(myZoomINLink);
                myStreetViewInfoDiv.appendChild(myNeedZoomDiv);
            }
            else {
                var myClickDiv = document.createElement("div");
                myClickDiv.innerHTML = "<p>Drag me onto a blue outlined street.<br/>You can also just click on a blue outlined street.</p>";
                myStreetViewInfoDiv.appendChild(myClickDiv);
            }; //end if zoom is at right level

            me._markerGuy.openInfoWindow(myStreetViewInfoDiv);
        }
        else {
            me._ShowPanorama();
            map.setCenter(myLatLng, 15, G_NORMAL_MAP);
        }; //end ifelse first time viewed
    };                             //end function
    //END REGION: Private Methods**************************************************


    //REGION: Panoramic Event Handlers*********************************************
    this._OnYawChange = function(pNewYaw) {
        var myGuyNumIcons = 16;
        var myGuyAngularRes = 360 / myGuyNumIcons;

        if (pNewYaw < 0) {
            pNewYaw += 360;
        };
        var myGuyImageNum = Math.round(pNewYaw / myGuyAngularRes) % myGuyNumIcons;
        var myGuyImageUrl = "http://maps.google.com/intl/en_us/mapfiles/cb/man_arrow-" + myGuyImageNum + ".png";
        me._markerGuy.setImage(myGuyImageUrl);
    };  //end function

    this._OnNewLocation = function(pLocation) {
        var myLatLng = pLocation.latlng;
        me._lastMarkerLocation = me._markerGuy.getLatLng();
        me._markerGuy.setLatLng(myLatLng);
    }; //end function



    this._HandlePanoErrors = function(pErrorCode) {
        if (pErrorCode == 603) {
            alert("Error: Flash doesn't appear to be supported by your browser");
            return;
        }; //end if error 603 NO FLASH

        //Do nothing else for other errors at this point...
    }; //end function

    //END REGION: Panoramic Event Handlers*****************************************




    //REGION: Marker Guy Event handlers********************************************

    this._OnDragStart = function() {
        //close the info window if it is open
        me._markerGuy.closeInfoWindow();
    }; //end function

    this._OnDragging = function() {
        //TODO: animate cursor like on Google maps
    }; //end function

    this._OnDragEnd = function() {
        //the marker guy has been dragged, we need to reposition the marker guy 
        //and show the pano if he was released in an area with street view
        var myLatLng = me._markerGuy.getLatLng();
        me._client.getNearestPanorama(myLatLng, me._GetNearestPanoramaResponse);
    }; //end function

    //END REGION: Marker Guy Event handlers****************************************

    //CONSTRUCTOR: ****************************************************************
    return new function() {
        me._InitializePanorama();
        this.StopStreetView = me._CleanUP;
        this.ToggleStreetViewOverlay = me._ToggleStreetViewOverlay;
        this.MapClicked = me._MapClicked;
    };
    //END CONSTRUCTOR: *************************************************************

}; //end class Streetview Controller




