function Direction(opt){
    var me = this;
    
    this.isDeviation = false;
    this.isFocus = true;
    this.isNew = true;
    this.phaseId = 'phase_1';
    this.isDirectionsSenseShow = false;
    this.draggable = false;
    this.isOldGeometry = false;
    
    this.directionsService = null;
    this.directionsRenderer = null;
    this.directionSign = null;
    
    this.points = null;

    this.stepsPoints = null;
    this._speedValue = -1;
    this.speed = new Speed();
    
    this.helperMarker = null;
    this.actionsHistory = null;
    this.event = null;

    this.allowCheck = true;

    this.initialize(opt || {});
    
    if(checkInterface(this, IGeometry)){
        return;
    }
};
Direction.prototype.initialize = function(opt){
    var me = this;
    this.map = opt.map;

    this.actionsHistory = new Array();
    
    this.isNew = true;
    this.isOldGeometry = false;
    this.isDirectionsSenseShow = false;
    this.isFocus = true;
    this.speed = new Speed();
    this.draggable = true;
    
    this.stepsPoints = null;

    this.points = new Array();
    this.directionSign = new DirectionSign();
    this.directionsService = new google.maps.DirectionsService();
    this._speedValue = -1;
    this.allowCheck = true;
    
    this._initDirectionRendered();
};

Direction.prototype._initDirectionRendered = function(){
    var me = this;
    this.directionsRenderer = new google.maps.DirectionsRenderer({
        map: this.map,
        draggable: this.draggable,
        polylineOptions: {
            strokeWeight: 2,
            strokeColor: '#112233'
        },
        preserveViewport: true
    });
    this.event = google.maps.event.addListener(this.directionsRenderer, 'directions_changed', function(){
        me.recalculatePoints(me);
    });
}

Direction.prototype.length = function(){
    return this.geometryPath().length;
};

Direction.prototype.addPoint = function(position){
    if(!this.isFocus)
        return;

    this.points.push(position);
    this.draw();
};

Direction.prototype.setPath = function(value){
    this.points = value;
    this.draw();
}

Direction.prototype.draw = function(){
    if(this.points.length==1){
        if(this.helperMarker != null)
            this.helperMarker.setMap(null)
        this.helperMarker = new google.maps.Marker({
            position: this.points[0],
            map: this.map
        })
    }else{
        if(this.helperMarker != null){
            this.helperMarker.setMap(null);
        }
    }
        
    if(this.points.length < 2)
        return;

    var me = this;
    
    var waypoints = [];
    if(this.points.length>2){
        for(var i=1; i<this.points.length - 1; i++){
            var item = this.points[i];
            waypoints.push({
                location: item
            });
        }
    }
    
    var directionRequest = {
        origin: this.points[0],
        waypoints: waypoints,
        destination: this.points[this.points.length - 1],
        travelMode: google.maps.DirectionsTravelMode.DRIVING
    }
    
    this.directionsService.route(directionRequest, function(result, status){
        if(status == google.maps.DirectionsStatus.OK){
            me.directionsRenderer.setDirections(result);
            var opt = me.generateOptions();
            me.directionsRenderer.setOptions({
                draggable: me.draggable,
                polylineOptions: opt
            });
        }
    });
};

Direction.prototype.generateOptions = function(){
    var opt = helpersGenerateStyle(this.isFocus, this.isDeviation, this.isNew, this.isOldGeometry);
    return opt;
};

Direction.prototype.recalculatePoints = function(){
    var me = this;
    var result = this.directionsRenderer.getDirections();

    this.speed.setDirectionsRenderer(this.directionsRenderer);
    this.speed.calculateSpeed();
	
    var route = result.routes[0];
    this.points = new Array();
   
    this.points.push(route.legs[0].start_location);

    for(var i=0;i<route.legs.length;i++){
        var leg = route.legs[i];
        var via_waypoint = leg.via_waypoint;
        for(var j=0;j<via_waypoint.length;j++){ 
            this.points.push(via_waypoint[j].location);
        }
        this.points.push(leg.end_location);
    }

    //direction sign
    if(!this.showDirectionsSense)
        return;
    this.showDirectionsSense(this.isDirectionsSenseShow);

    $('body').trigger('onDirectionChangedEditMap',{
        object: me,
        allowCheck: me.allowCheck
    });


    var  p = new Array();
    for(var i = 0, item; item = this.points[i]; i++){
        p.push(item);
    }
    this.actionsHistory.push(p);

    //check last 2 points
    var item1 = this.actionsHistory[this.actionsHistory.length - 2];
    var item2 = this.actionsHistory[this.actionsHistory.length - 1];

    if(item1 == null || item2 == null)
        return;

    var ok = false;
    if(item1.length != item2.length)
        ok = false;
    else{
        for(var i=0; i<item1.length; i++){
            if(item1[i].toString() == item2[i].toString()){
                ok = true;
            }else{
                ok = false;
            }
        }
    }
    if(ok == true && this.actionsHistory.length > 1){
        this.actionsHistory.splice(this.actionsHistory.length - 1, 1);
    }
};

Direction.prototype.showDirectionsSense = function(value){
    this.isDirectionsSenseShow = value;
    this.directionSign.ClearMarkers();
    if(this.isDeviation && this.isDirectionsSenseShow){
        var path = this.geometryPath();
        this.directionSign.SetPoints(path);
        this.directionSign.GeneratePoints(DEVIATIONICONSSTEPS);
        this.directionSign.DrawMarkers(this.map);
    }
};


Direction.prototype.setOptions = function(options){
    var me= this;
    google.maps.event.removeListener(this.event);
    this.directionsRenderer.setOptions(options);
    if(this.directionsRenderer != null){
        var a = this.directionsRenderer.getDirections();
        if(a != null){
            this.directionsRenderer.setDirections(a);
        }
    }
    this.event = google.maps.event.addListener(this.directionsRenderer, 'directions_changed', function(){
        me.recalculatePoints(me);
    });
};

Direction.prototype.moveBackOneStep = function(map){
    var item = null;
    if(this.actionsHistory.length > 1){
        item = this.actionsHistory[this.actionsHistory.length - 2];
    }else{
        item = new Array();
        if(this.actionsHistory[0] != null && this.actionsHistory[0][0] != null){
            item.push(this.actionsHistory[0][0]);
        }else{
            //don't remove last point
            return;
        }
    }
    this.actionsHistory.pop();

    this.clear();
    
    this.setPath(item);
    this.setOptions({
        map: map
    });
}

Direction.prototype.clear = function(){
    google.maps.event.removeListener(this.event);
    this.setOptions({
        map: null
    });
    if(this.helperMarker != null)
        this.helperMarker.setOptions({
            map: null
        })
    this.points = new Array();
    this.directionSign.ClearMarkers();
    this._initDirectionRendered();
};

Direction.prototype.geometryPath = function(){
    var path = new Array();
    
    var result = this.directionsRenderer.getDirections();
    if(result == null){
        return path;
    }
    
    var route = result.routes[0];

    for(var i=0;i<route.legs.length;i++){
        var leg = route.legs[i];
        for(var j=0;j<leg.steps.length;j++){ 
            var step = leg.steps[j];
            for(var k=0;k<step.path.length;k++){
                path.push(step.path[k]);
            }
        }
    }
    return path;
};

Direction.prototype._getMarkersPoints = function(){
    var result = this.directionsRenderer.getDirections();

    var route = result.routes[0];
    var points = new Array();

    points.push(route.legs[0].start_location);

    for(var i=0;i<route.legs.length;i++){
        var leg = route.legs[i];
        var via_waypoint = leg.via_waypoint;
        for(var j=0;j<via_waypoint.length;j++){
            points.push(via_waypoint[j].location);
        }
        points.push(leg.end_location);
    }
    var val = '';
    for(var i=0, item; item = points[i]; i++){
        val += item.lat().toString() + ',' + item.lng().toString() + ';';

    }
    return val;
}

Direction.prototype.getGeometryJSON = function(){
    var path = this.geometryPath();
    var geometry = new Array();
    for(var i=0, item; item = path[i]; i++){
        geometry.push({
            lat: item.lat(),
            lng: item.lng()
        })
    }
    //remove deviation when calculate street
    var stepsPoints = null;
    if(this.isDeviation == false){
        stepsPoints= this._getStepsPoints();
    }
    var values = {
        isDeviation: this.isDeviation == true ? 1 : 0,
        geometry: geometry,
        deviationArrows: this.directionSign.GetPoints(),
        stepsPoints: stepsPoints,
        markersPoints: this._getMarkersPoints(),

        kmlFlag: 1
    };
    return values;
};



Direction.prototype._getStepsPoints = function(){
    var geometry = new Array();
    var result = this.directionsRenderer.getDirections();
    var route = result.routes[0];
    for(var i=0;i<route.legs.length;i++){
        var leg = route.legs[i];
        for(var j=0;j< leg.steps.length;j++){
            var step = leg.steps[j];
            geometry.push({
                lat: step.start_location.lat(),
                lng: step.start_location.lng()
            });
            geometry.push({
                lat: step.end_location.lat(),
                lng: step.end_location.lng()
            });
        }
    }
    this.stepsPoints = geometry;
    var values = '';
    for(var i=0, item; item = this.stepsPoints[i]; i++){
        values += item.lat + ',' + item.lng + ';';
        
    }
    return values;
}
            
Direction.prototype.focus = function(){
    this.isFocus = true;
    var opt = this.generateOptions();
    this.setOptions({
        draggable: true,
        polylineOptions: opt
    });
    this.showMarkers(true);
};

Direction.prototype.loseFocus = function(){
    this.isFocus = false;
    var opt = this.generateOptions();
    this.setOptions({
        draggable: false,
        polylineOptions: opt
    });
    this.showMarkers(false);
};
Direction.prototype.showMarkers = function(value){
    this.setOptions({
        draggable: value,
        markerOptions: {
            visible: value
        }
    });  
};

Direction.prototype.setDirectionsSense = function(value){
    };

Direction.prototype.setSpeed = function(value){
    this._speedValue = value;
};
Direction.prototype.getSpeed = function(){
    if(this._speedValue != -1){
        return this._speedValue;
    }
    return this.speed.maxStepSpeed;
};

Direction.prototype.getBounds = function(){
    var bounds = new google.maps.LatLngBounds();
    for(var i=0, item; item = this.points[i]; i++){
        bounds.extend(item);
    }
    return bounds;
}

Direction.prototype.length = function(){
    return this.points.length;
}

Direction.prototype.getMarkersPoints = function(){
    return this._getMarkersPoints();
}
