if (typeof window !== 'undefined'){ global = this; }
$puts = function(){ console.log.apply(console,arguments) };
nil = null;

$$ctor = function(){};

$console = console;
$set_interval = setInterval;
$clear_interval = clearInterval;
$set_timeout = setTimeout;
$clear_timeout = clearTimeout;

$after = $delay = function(msec,cb){ return $set_timeout(cb,msec);}
$every = function(msec,cb){ return $set_interval(cb,msec);}

$to_f = $tofloat = parseFloat;
$to_i = $toint = parseInt;
$to_s = $tostring = function(v){ return String(v); };
$abs = function(v){ return Math.abs(v);};
$ceil = function(v){ return Math.ceil(v);};
$floor = function(v){ return Math.floor(v);};

$uid = function(){ return $uid.next++; };
$uid.next = 0;

$const_get = function(name){ return global[name]; }

$create = function(proto){
  var Class = function(){}
  Class.prototype = proto;
  return new Class()
}

// Creating the module instance-prototype
Module = function(){}
Module.prototype = Object.create(Object.prototype)

// Creating the class instance-prototype
Class = function(){}
Class.prototype = Object.create(Module.prototype)

Class.prototype.inherited = function(subclass){};
Class.prototype.method_added = function(method_name){};
Class.prototype.singleton_method_added = function(method_name){};

Class.prototype.define_method = function(name, method){
  this.prototype[name] = method;
  __method_added(this,name);
  return method;
};

// Basic object is instance of class
DObject = new Class;
DObject.__object_id__ = $uid();
DObject.__ctor__ = function BaseClass(){};
DObject.prototype = DObject.__ctor__.prototype = {};
DObject["@classname"] = 'Object';
DObject.Object = DObject;
Kernel = DObject;

DObject.__scope__ = __scope = global;
DObject.name = function(){ return this["__named__"] }
DObject.prototype.p = DObject.p = $puts;
DObject.prototype["class"] = function(){ return this["__class__"] }

DObject.def_class = function(classname, superclass, body){

  if(!superclass) superclass = DObject;
   
  var klass, proto, scope;

  // check if the class already exists  
  if(this.__scope__.hasOwnProperty(classname)){
    klass = this.__scope__[classname];
    proto = klass.prototype;
    scope = klass.__scope__;

    // this is a native class, set ctor!
    if(!scope){
      klass.__ctor__ = klass;
      scope = klass.__scope__ = $create(this.__scope__);
    }

  } else {
    // crete the class here
    klass = $create(superclass)
    proto = $create(superclass.prototype)
    scope = klass.__scope__ = $create(this.__scope__);

    klass.__super__ = superclass;
    klass.__ctor__ = undefined;
    klass.__named__ = classname;
    klass['@name'] = classname;
    proto.__class__ = klass;
    klass.prototype = proto;

    // adding new class to the scope
    this[classname] = this.__scope__[classname] = klass;
    // Tell the superclass about the inheritance
    superclass.inherited(klass)
  }
  
  body.call(klass, scope, klass)
  return klass;
}

DObject.def_tag = function(tagname, supertag, body){

  if(tagname == 'NODE_TAG') supertag = DObject;
  else supertag = DObject[supertag];
  // Should it always be defined on DObject? Really?
  return DObject.def_class(tagname, supertag, body);
}

global.__ctor = function(obj){
  return obj.__ctor__ || obj;
}

global.__tag = function(name, id, classes, attributes, children){
  var tag, type;
  
  if(id){
    type = DObject[id.toUpperCase()+"_TAG_ID"];
    if(!name && !type) name = 'DIV';
  }

  // Check if the id matches the correct type
  if(!type) type = DObject[name.toUpperCase()+"_TAG"];
  
  if(type){
    return type.create(name, id, classes, attributes, children);
  } else {
    // Should maybe raise a warning here!
    flag = name.toLowerCase()+'_'
    return DObject.NODE_TAG.create(name, id, classes, attributes, children, flag);
  }
}

function $__tag(node){
  var type;

  if(!node) return null;
  if(node["@view"]) return node["@view"];

  var name = node.nodeName.toUpperCase()+"_TAG";
  if(name.substr(0,1) == '#') name = name.substr(1);

  if(node.id) type = DObject[node.id.toUpperCase()+"_TAG_ID"]
  type = type || DObject[name] || DObject["NODE_TAG"];
  var view = new type.__ctor__(node, {}, null, true);
  return node["@view"] = view;
}

global.__tagid = function(id){
  var node = document.getElementById(id);
  if(node) return $__tag(node);

  var type = DObject[id.toUpperCase()+"_TAG_ID"];
  if(type){
    console.log('found ID type!!!')
    return type.create(null,null,[],{},[]);
  }
  return null;
}

global.__msel = function(selector, scope){
  return new (Selector.__ctor__)(selector, scope);
}

global.__sel = function(selector, scope){
  return Selector.first(selector, scope);
}

global.__method_added = function(obj, name) {
  if(obj.method_added) obj.method_added(name);
}

global.__singleton_method_added = function(obj, name) {
    if(obj.singleton_method_added) obj.singleton_method_added(name);
}

// Global helpers
$win = $window = this; // NOT correct on server!
$doc = $document = this.document;
$$base = DObject;

