"use strict";

var cycl = require('cycl'),
    processor = require('./processor.js'),
    presets = require('./presets.js'),
    rubix = require('./rubix.js'),
    Props = require('./props.js'),
    Pointer = require('../input/pointer.js'),
    KEY = require('../opts/keys.js'),
    Data = require('../bits/data.js'),

    Action = function () {
        var self = this;
        
        // Create value manager
        this.values = new Values();
        
        // Create new property manager
        this.props = new Props();

        // Create data store
        this.data = new Data();
        
        // Register process wth cycl
        this.process = cycl.newProcess(function (framestamp, frameDuration) {
            processor.action(self, framestamp, frameDuration);
        });
    };

Action.prototype = {

    // [number]: Progress represented in a range of 0 - 1
    progress: 0,
    
    // [number]: Time elapsed in ms
    elapsed: 0,

    /*
        Play the provided actions as animations
        
        Syntax
            .play(playlist, [override])
                @param [string]: Playlist of presets
                @param [object]: (optional) Override object
                
            .play(params)
                @param [object]: Action properties
                
        @return [Action]
    */
    play: function (defs, override) {
        return this.start(KEY.RUBIX.TIME, presets.createBase(defs, override));
    },
    
    /*
        Track values to mouse, touch or custom Input
        
        Syntax
            .track(preset, [override], input)
                @param [string]: Name of preset
                @param [object]: (optional) Override object
                @param [event || Input]: Input or event to start tracking
                
            .track(params, input)
                @param [object]: Action properties
                @param [event || Input]: Input or event to start tracking
                
        @return [Action]
    */
    track: function (defs) {
        var hasAllArgs = (arguments[2] !== undefined),
            input = hasAllArgs ? arguments[2] : arguments[1],
            override = hasAllArgs ? arguments[1] : {},
            base = presets.createBase(defs, override);
        
        // If we have an input, check if it's a custom input.
        // Create a new pointer if it isn't
        if (input) {
            base.input = (input.current) ? input : new Pointer(input);
            base.inputOrigin = base.input.get();
        }
        
        return this.start(KEY.RUBIX.INPUT, base);
    },

    /*
        Run Action indefinitely
        
        Syntax
            .run(preset, [override])
                @param [string]: Name of preset
                @param [object]: (optional) Override object
                
            .run(params)
                @param [object]: Action properties
                
        @return [Action]
    */
    run: function (defs, override) {
        return this.start(KEY.RUBIX.RUN, presets.createBase(defs, override));
    },
    
    /*
        Start Action

        @param [string]: Name of processing type to sue
        @param [object]: Base Action properties to apply
        @return [Action]
    */
    start: function (processType, base) {
        this.resetProgress();
        this.change(processType, base);
        this.isActive(true);
        this.started = utils.currentTime() + this.props.get('delay');
        this.framestamp = this.started;
        this.firstFrame = true;
        
        this.process.start();
        
        return this;
    },
    
    /*
        Stop current Action process
    */
    stop: function () {
        this.isActive(false);
        this.process.stop();
        
        return this;
    },
    
    /*
        Pause current Action
    */
    pause: function () {
        this.stop();
        
        return this;
    },
    
    /*
        Resume a paused Action
    */
    resume: function () {
        this.started = utils.currentTime() - this.elapsed;
        this.framestamp = this.started;
        
        this.process.start();
        
        return this;
    },
    
    /*
        
    */
    reset: function () {
        this.resetProgress();
        this.values.reset();
        
        return this;
    },
    
    resetProgress: function () {
        this.progress = 0;
        this.elapsed = 0;
    },
    
    reverse: function () {
        this.progress = calc.difference(this.progress, 1);
        this.elapsed = calc.difference(this.elapsed, this.duration);
        this.values.reverse();

        return this;
    },
    
    /*
        Check for next steps and perform, stop if not
    */
    next: function () {
        var nexts = [{
                key: 'loop',
                callback: this.reset
            }, {
                key: 'yoyo',
                callback: this.reverse
            }],
            possibles = nexts.length,
            hasNext = false;
            
        for (var i = 0; i < posssbiles; ++i) {
            if (this.checkNextStep(nexts[i].key, nexts[i].callback)) {
                hasFuture = true;
                break;
            }
        }

        if (!hasNext) {
            this.stop();
        }
    },
    
    /*
        Check next step
        
        @param [string]: Name of step ('yoyo' or 'loop')
        @param [callback]: Function to run if we take this step
    */
    checkNextStep: function (key, callback) {
        var stepTaken = false,
            step = this.props.get(key),
            count = this.props.get(key + 'Count'),
            forever = (yoyo === true);
            
        if (forever || utils.isNum(step)) {
            ++count;
            this.props.set(key + 'Count', count);
            
            if (forever || count <= step) {
                callback();
                stepTaken = true;
            }
        }
    },
    
    /*
        Next in playlist
        
        
    */
    playNext: function () {
        var stepTaken = false,
            playlist = this.props.get('playlist'),
            platlistLength = playlist.length,
            playhead = this.props.get('playhead'),
            next = {};
            
        // Check we have a playlist
        if (playlistLength > 1) {
            ++playhead;
            
            if (playhead < playlistLength) {
                next = presets.getDefined(playlist[playhead]);
                next.playhead = playhead;
                
                this.change(KEY.RUBIX.TIME, next);
                stepTaken = true;
            }
        }
    },
    
    setValue: function (key, value) {
        this.values.set(key, value);
    },
    
    getValue: function (key) {
        return this.values.get(key);
    },
    
    setProp: function (key, value) {
        this.props.set(key, value);
    },
    
    getProp: function (key) {
        return this.props.get(key);
    },
    
    /*
        Is Action active?
        
        @param [boolean] (optional): If provided, will set action to active/inactive
        @return [boolean]: Active status
    */
    isActive: function (active) {
        if (active !== active) {
            this.active = active;
        }
        
        return this.active;
    },
    
    /*
        Change Action properties
        
        @param [string]: Type of processing rubix to use
        @param [object]: Base properties of new input
    */
    change: function (processType, base) {
        // Assign the processing rubix
        base.rubix = rubix[processType];

        this.props.apply(base);
        this.values.apply(base.values, this.props);

        this.origin = {};
        // Create origins
        for (var key in this.values) {
            if (this.values.hasOwnProperty(key)) {
                this.origin[key] = this.values[key].current;
            }
        }
    }
    
};

module.exports = Action;
@@ -5119,14 +5119,12 @@
  has
-Future
+Next
  = t
@@ -5175,16 +5175,24 @@
       %7D%0A
+        
 %0A       
@@ -5204,16 +5204,41 @@
 !hasNext
+ && !this.checkNextStep()
 ) %7B%0A    
@@ -5974,26 +5974,8 @@
 ist%0A
-        %0A        %0A
     

check next in playlist