(function() {
  var AbstractState, AbstractStateMachine, Entity, Link, State, StatechartManager, check, sanitize, _;
  var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (__hasProp.call(this, i) && this[i] === item) return i; } return -1; }, __slice = Array.prototype.slice;

  _ = require("underscore");

  check = require("validator").check;

  sanitize = require("validator").sanitize;

  root.jQuery = require("jQuery");

  root.window = {};

  root.window.SC = {};

  root.window.SproutCore = {};

  root.YES = true;

  root.NO = false;

  root.sc_require = function() {};

  require("../vendor/sproutcore/runtime");

  require("../vendor/sproutcore/statechart");

  StatechartManager = SC.Object.extend(SC.StatechartManager, {
    autoInitStatechart: true,
    statesAreConcurrent: true
  });

  AbstractStateMachine = (function() {

    __extends(AbstractStateMachine, StatechartManager);

    AbstractStateMachine.debug = false;

    AbstractStateMachine.statesAreSet = false;

    function AbstractStateMachine() {
      if (this.constructor.statesAreSet === false) {
        if (AbstractStateMachine.debug === true) {
          console.log("No states are set. Set an empty one");
        }
        this.constructor.states(function() {
          return this.state("Empty");
        });
      }
      AbstractStateMachine.__super__.constructor.apply(this, arguments);
    }

    AbstractStateMachine.prototype.update = function(key, value) {
      var validator;
      if (validator = this["" + key + " validator"]) {
        if (value !== void 0) {
          validator.call({
            value: (function() {
              return check(value);
            })()
          });
        }
      }
      return this.set.apply(this, arguments);
    };

    AbstractStateMachine.prototype.read = function(key) {
      return this.get.apply(this, arguments);
    };

    AbstractStateMachine.states = function(body) {
      if (body) return body.call(this);
    };

    AbstractStateMachine.state = function(state, options, body) {
      var name, _ref;
      this.statesAreSet = true;
      _ref = AbstractStateMachine._parseArgs.apply(AbstractStateMachine, arguments), state = _ref.state, name = _ref.name, options = _ref.options, body = _ref.body;
      AbstractStateMachine._log("Create global state <" + name + "> from a class: " + (state !== null ? 'yes' : 'no'));
      return AbstractStateMachine._createState(this, state, name, options, body);
    };

    AbstractStateMachine._parseArgs = function(state, options, body) {
      var name;
      if (state instanceof Object) {
        name = state.prototype.name;
      } else if (typeof state === "string") {
        name = state;
        state = null;
      }
      if (typeof options === "object") {
        _(options).defaults({
          concurrent: false
        });
      } else if (typeof options === "function") {
        body = options;
        options = {
          concurrent: false
        };
      } else if (!options) {
        options = {
          concurrent: false
        };
      }
      return {
        state: state,
        name: name,
        options: options,
        body: body
      };
    };

    AbstractStateMachine._createState = function(context, CustomState, name, options, body) {
      var NewState;
      NewState = State.design();
      NewState.prototype.substatesAreConcurrent = options.concurrent;
      this._log(" - Has concurrent substates: " + (options.concurrent ? 'yes' : 'no'));
      context.prototype[name] = NewState;
      this._createEventHandlers(NewState, CustomState);
      if (body) return body.call(NewState);
    };

    AbstractStateMachine._setInitialSubstateOnParent = function(ParentState, name) {
      var initialSubstate, initialSubstateMessage;
      if (ParentState.prototype.substatesAreConcurrent !== true && !ParentState.prototype.initialSubstate) {
        ParentState.prototype.initialSubstate = initialSubstate = name;
      }
      initialSubstateMessage = initialSubstate != null ? "<" + initialSubstate + ">" : 'no';
      return this._log(" - Has initial substate: " + (initialSubstate != null ? initialSubstateMessage : 'no'));
    };

    AbstractStateMachine._createEventHandlers = function(NewState, CustomState) {
      var eventHandler, eventHandlers, properties, property, _i, _len, _results;
      if (CustomState instanceof Object) {
        properties = _(CustomState.prototype).keys();
        eventHandlers = (function() {
          var _i, _len, _results;
          _results = [];
          for (_i = 0, _len = properties.length; _i < _len; _i++) {
            property = properties[_i];
            if (typeof CustomState.prototype[property] === "function" && property !== "constructor") {
              _results.push(property);
            }
          }
          return _results;
        })();
        _results = [];
        for (_i = 0, _len = eventHandlers.length; _i < _len; _i++) {
          eventHandler = eventHandlers[_i];
          _results.push(NewState.prototype[eventHandler] = CustomState.prototype[eventHandler]);
        }
        return _results;
      }
    };

    AbstractStateMachine._createTransitionStates = function(eventName, FromState, options) {
      var toState, _base, _ref;
      if ((_ref = (_base = FromState.prototype).transitionStates) == null) {
        _base.transitionStates = [];
      }
      if (typeof options.goto === "string") {
        toState = options.goto;
        return FromState.prototype.transitionStates.push("" + eventName + "." + toState);
      } else if (typeof options.goto === "array") {
        return (function(toState) {
          var _i, _len, _ref2, _results;
          _ref2 = options.goto;
          _results = [];
          for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
            toState = _ref2[_i];
            _results.push(FromState.prototype.transitionStates.push("" + eventName + "." + toState));
          }
          return _results;
        })(toState);
      }
    };

    AbstractStateMachine._createGotoHandler = function(eventName, FromState) {
      return FromState.prototype.goto = function(state) {
        var _ref;
        if (_ref = "" + eventName + "." + state, __indexOf.call(this.transitionStates, _ref) >= 0) {
          return this.statechart.gotoState(state, this.name);
        } else {
          throw new Error("You can't goto state <" + state + "> through event [" + eventName + "] in state <" + this.name + ">");
        }
      };
    };

    AbstractStateMachine.attributes = function(body) {
      var attribute, attributes, config, validator, value, _results;
      attributes = body ? body.call(this) : void 0;
      _results = [];
      for (attribute in attributes) {
        config = attributes[attribute];
        value = config.value === void 0 ? void 0 : config.value;
        if (config.validate) {
          this.prototype["" + attribute + " validator"] = validator = config.validate;
          if (value !== void 0) {
            validator.call({
              value: (function() {
                return check(value);
              })()
            });
          }
        } else {
          this.prototype["" + attribute + " validator"] = null;
        }
        _results.push(this.prototype[attribute] = value);
      }
      return _results;
    };

    AbstractStateMachine._log = function(message) {
      if (this.debug === true) return console.log(message);
    };

    AbstractStateMachine.prototype.isIn = AbstractStateMachine.prototype.stateIsEntered;

    AbstractStateMachine.prototype.isCurrentlyIn = AbstractStateMachine.prototype.stateIsCurrentState;

    AbstractStateMachine.prototype.emit = function() {
      var args, eventName;
      eventName = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
      return this.sendEvent.apply(this, [eventName].concat(__slice.call(args), [function() {}]));
    };

    return AbstractStateMachine;

  })();

  module.exports.Link = Link = (function() {

    __extends(Link, AbstractStateMachine);

    function Link() {
      Link.__super__.constructor.apply(this, arguments);
    }

    return Link;

  })();

  module.exports.Entity = Entity = (function() {

    __extends(Entity, AbstractStateMachine);

    function Entity() {
      Entity.__super__.constructor.apply(this, arguments);
    }

    return Entity;

  })();

  AbstractState = SC.State.extend();

  module.exports.State = State = (function() {

    __extends(State, AbstractState);

    function State() {
      State.__super__.constructor.apply(this, arguments);
    }

    State.state = function(state, options, body) {
      var name, _ref;
      _ref = AbstractStateMachine._parseArgs.apply(AbstractStateMachine, arguments), state = _ref.state, name = _ref.name, options = _ref.options, body = _ref.body;
      AbstractStateMachine._setInitialSubstateOnParent(this, name);
      AbstractStateMachine._log("Create global state <" + name + "> from a class: " + (state !== null ? 'yes' : 'no'));
      return AbstractStateMachine._createState(this, state, name, options, body);
    };

    State.event = function(name, options) {
      if (typeof options === "object") {
        if (options.goto) {
          AbstractStateMachine._createTransitionStates(name, this, options);
          return AbstractStateMachine._createGotoHandler(name, this);
        }
      }
    };

    return State;

  })();

}).call(this);
