-'use strict';
+'use strict'
 
 # ES 5 compability functions
-Object.keys or= (o) -> name for own name of o
 Array.isArray or= (a) -> a.push is Array.prototype.push and a.length?
 
-# CommonJS flag
-isCommonJS = exports?
+# Check for potential server-side javascript
+hasModule = module?.exports?
 
 # Function to check for JavaScript file ending
-hasExtension = (filename, extension) -> 
+hasExtension = (filename, extension) ->
   return undefined unless filename?
   
   filename.lastIndexOf(extension) is filename.length - extension
 
 isJavaScriptFile = (filename) -> hasExtension filename, '.js'
 
+
 # Wrapper function
 do (root = module?.exports ? this) ->
-  cache = {}
-  queue = {}
-  pathSep = '/'
-  
+
+  # Loading script
   loadScriptFile = (filename, callback) ->
-    unless isCommonJS
+    unless hasModule
       scriptElem = root.document.createElement 'script'
       
       scriptElem.async = true

        
      if callback
        scriptElem.onload = scriptElem.onreadystatechange = ->
          rs = @readyState;
          return undefined if rs and rs isnt 'complete' and rs isnt 'loaded'
          callback()
        
      firstScriptElem = root.document.getElementsByTagName('script')[0]
      firstScriptElem.parentNode.insertBefore scriptElem, firstScriptElem
      
  moloDefine = (name, body) ->
    # Abort if no name or no body
    return unless name or body
    
    # If name is a function, then just call the function
    if typeof name is 'function' then return name.apply @
    
    # If body, add it to the cache directly, else queue it
    # Special case: body is allowed to be an object (add it to cache)
    if typeof body is 'object' then return cache[name] = body
    
    # If function, call the function and add it to the cache
    if typeof body is 'function' then return cache[name] = body()
    
    queue[name] = define
    
  moloRequire = (name, callback) ->
    if Object.hasOwnProperty.call cache, name then return callback cache[name]
    
    if Object.hasOwnProperty.call queue, name
      name
    

  moloFunc = (name, defines) ->
    # TODO: Add module name always to queue and remove it if all dependencies have been met
    # Currently, the module will only be added if it has any depedencies and cannot be
    # resolved directly
    
    # Skip flag to skip the rest of the function
    skipFunc = false
    
    defObject = {}

    # If name is not a string, it's an anonymous module (Put defines parameter in the correct order)
    if typeof name isnt 'string'
      # If name is an array, just load dependencies
      if Array.isArray(name) 
        if Object.keys(defines).length > 0
          defines.require = name
        else
          defines =
            require: name

        skipFunc = true
      else 
        [name, defines] = [undefined, name]

    # Skip if no factory has been defined
    return undefined unless defines

    # Get properties from defines if it's an object, else they are no dependencies and take the function as the factory
    if typeof defines is 'function' then define = defines else {define, require: deps, context} = defines

    # Default parameters, if they have not been defined yet
    deps = [] unless deps?
    context = @ unless context?

    # If a single dependency has been declared as a string, make it into an array
    if typeof deps is 'string' then deps = [deps]

    # Get the result of cached dependencies
    cacheDeps = []

    for i in deps
      # Need to check for hasOwnProperty
      # Checking for cache[i] is not strict enough
      # because a module could have undefined, null, 0 or an empty string
      # as its export value
      if Object.hasOwnProperty.call cache, i
        cacheDeps.push cache[i]
      else
        # Plugin functionality
        pluginName = i.split('!')[1]
        
        scriptLoader = root.molo.scriptLoader
        
        # If a script is defined as 'my/script!' it will try to resolve the 
        # dependency on the same page
        scriptLoader = false if pluginName is ''
        
        if scriptLoader
          if isJavaScriptFile(root.molo.paths[name])
            # If the path is complete (e.g. 'js/lib/mymodule.js') take that as a path
            scriptPath = root.molo.paths[name]

                prePath = root.molo.paths[p]

            scriptPath = if prePath then "#{prePath}#{pathSep}#{i}.js" else "#{i}.js"
        
          loadScriptFile scriptPath, ->
            #root.molo.require i, callback, context
        
        
  # Additional export functions
  
  # Delete a single module from cache, which forces it to
  # reload this module if it comes up as a dependency the
  # next time
  root.molo.delete = (name) ->
    delete cache[name] if cache[name]
    delete queue[name] if queue[name]

  # Completely clear all caches
  root.molo.clear = ->
    cache = {}
    queue = {}
    
  
  # Molo main shorthand
  mainHasBeenCalled = false
  
  root.molo.main = (name, callback) ->
    if mainHasBeenCalled then throw new TypeError('molo.main can only be called once.')

    root.molo.require name, callback
    
    moloHasBeenCalled = true
    

  # Alternative module decleration
  root.unit = (name, body) ->
    {requires, defines} = body
    
    root.molo.define name, requires, defines
