"use strict";

var Backbone = require('../../shim/backbone'),
    Marionette = require('../../shim/backbone.marionette'),
    $ = require('jquery'),
    _ = require('lodash'),
    turfArea = require('turf-area');

var MapModel = Backbone.Model.extend({
    defaults: {
        lat: 0,
        lng: 0,
        zoom: 0,
        areaOfInterest: null,           // GeoJSON
        halfSize: false
    },

    revertMaskLayer: function() {
        // If a mask layer is applied, remove it in favor of a traditional
        // area of interest polygon
        this.set('maskLayerApplied', false);
    },

    restructureAoI: function() {
        // The structure of the AoI is slightly different depending
        // on whether the shape was drawn or selected. It needs to
        // be consistent because Project is always expecting an
        // object with type='MultiPolygon', a coordinates attribute
        // and nothing else.
        if (this.get('areaOfInterest')) {
            var aoi = this.get('areaOfInterest').geometry ?
                      this.get('areaOfInterest').geometry :
                      this.get('areaOfInterest');

            if (aoi.type !== 'MultiPolygon') {
                if (aoi.type === 'Polygon') {
                    aoi.coordinates = [aoi.coordinates];
                } else if (aoi.type === 'FeatureCollection') {
                    aoi.coordinates = [aoi.features[0].geometry.coordinates];
                }

                aoi.type = 'MultiPolygon';
            }

            this.set('areaOfInterest', aoi);
        }
    }
});

var TaskModel = Backbone.Model.extend({
    defaults: {
        pollInterval: 500,
        timeout: 5000
    },

    url: function() {
        if (this.get('job')) {
            return '/api/' + this.get('taskType') + '/jobs/' + this.get('job') + '/';
        } else {
            return '/api/' + this.get('taskType') + '/start/' + this.get('taskName') + '/';
        }
    },

    pollForResults: function() {
        var defer = $.Deferred(),
            duration = 0,
            self = this;

        // Check the task endpoint to see if the job is
        // completed. If it is, return the results of
        // the job. If not, check again after
        // pollInterval has elapsed.
        var getResults = function() {
                if (duration >= self.get('timeout')) {
                    defer.reject();
                    return;
                }

                self.fetch()
                    .done(function(response) {
                        console.log('Polling ' + self.url());
                        if (response.status !== 'complete') {
                            duration = duration + self.get('pollInterval');
                            window.setTimeout(getResults, self.get('pollInterval'));
                        } else {
                            defer.resolve(response);
                        }
                    })
                    .fail(defer.reject);
        };

        window.setTimeout(getResults, self.get('pollInterval'));

        return defer.promise();
    }
});

var GeoModel = Backbone.Model.extend({
    M_IN_KM: 1000000,

    defaults: {
        name: '',
        shape: null,        // GeoJSON
        area: '0',
        units: 'm<sup>2</sup>',
    },

    initialize: function() {
        this.setDisplayArea();
    },

    setDisplayArea: function() {
        if (!this.get('shape')) { return; }

        var areaInMeters = turfArea(this.get('shape'));

        // If the area is less than 1 km, use m
        if (areaInMeters < this.M_IN_KM) {
            this.set('area', areaInMeters);
        } else {
            this.set('area', areaInMeters / this.M_IN_KM);
            this.set('units', 'km<sup>2</sup>');
        }
    }
});

var AreaOfInterestModel = GeoModel.extend({
    defaults: _.extend({
        place: 'Selected Area',
        can_go_back: false
    }, GeoModel.prototype.defaults)
});

module.exports = {
    MapModel: MapModel,
    TaskModel: TaskModel,
    GeoModel: GeoModel,
    AreaOfInterestModel: AreaOfInterestModel
};

@@ -1943,24 +1943,292 @@
   %7D%0A    %7D,%0A%0A
+    // Cancels any currently running jobs. The promise returned%0A    // by previous calls to pollForResults will be rejected.%0A    reset: function() %7B%0A        this.set(%7B%0A            'job': null,%0A            'result': null,%0A            'status': null%0A        %7D);%0A    %7D,%0A%0A
     pollForR
@@ -2331,16 +2331,59 @@
 f = this
+,%0A            expectedJob = self.get('job')
 ;%0A%0A     
@@ -2616,28 +2616,24 @@
             
-    
 if (duration
@@ -2655,32 +2655,186 @@
 imeout')) %7B%0A    
+            defer.reject();%0A                return;%0A            %7D%0A%0A            // If job was cancelled.%0A            if (expectedJob != self.get('job')) %7B%0A
                 
@@ -2838,34 +2838,33 @@
    defer.reject(
-);
+%7B
 %0A               
@@ -2874,37 +2874,137 @@
   re
-turn;%0A                %7D%0A%0A    
+set: %7B%0A                        job: expectedJob%0A                    %7D%0A                %7D);%0A                return;%0A            %7D%0A%0A
     
@@ -3040,20 +3040,16 @@
         
-   
- 
 .done(fu
@@ -3063,28 +3063,24 @@
 response) %7B%0A
-    
             
@@ -3141,28 +3141,24 @@
             
-    
 if (response
@@ -3199,36 +3199,32 @@
                 
- 
-   
 duration = durat
@@ -3251,28 +3251,24 @@
 Interval');%0A
-    
             
@@ -3352,28 +3352,24 @@
             
-  
-  
 %7D else %7B%0A   
@@ -3357,36 +3357,32 @@
        %7D else %7B%0A
-    
                 
@@ -3414,20 +3414,16 @@
 ponse);%0A
-    
         
@@ -3456,19 +3456,11 @@
     
-    %7D)%0A    
+%7D)%0A
     
@@ -3565,25 +3565,24 @@
 nterval'));%0A
-%0A
         retu

Allow TaskModel to be reset