Api        = require './index'
stringify  = Widgetic.JSON.stringify
Helper 	   = window.require 'spine/utils/helper'
url = (object,id=true)->
	u=(object.className or object.constructor.className).toLowerCase()+'s'
	if id and object.id and (not /^c\-[\d]+/.test object.id)
		u+='/'+ encodeURIComponent(object.id)
	u
class Base
	request: ->
		if Api.enabled
			return Widgetic.api.apply(Widgetic, arguments)

		def = Widgetic.Aye.defer()
		def.reject('Widgetic API is disabled.')
		return def.promise

class Singleton extends Base
	constructor: (@record) ->
		@model = @record.constructor

	reload: (options) ->
		@request(url(@record)).then(@recordResponse(options),@failedReload(options))

	create: (options) ->
		@request(url(@record,false),'POST',stringify(@record)).then(@recordResponse(options), @failedWithData(options))

	update: (options) ->
		isNew =  /^c\-[\d]+/.test @record.id
		@request(url(@record,not isNew),(if isNew then 'POST' else 'PUT'),stringify(@record)).then(@recordResponse(options), @failedWithData(options))

	destroy: (options) ->
		@request(url(@record),'DELETE').then(@recordResponse(options), @failedWithData(options))

	# Private
	recordResponse: (options = {}) =>
		(data) =>
			if (data = if (blank = Helper.isBlank(data)) then false else @model.fromJSON(data))
				Api.disable =>
					@record.changeID(data.id) if data.id and @record.id isnt data.id
					@record.updateAttributes {id: data.id}, fromApi:true

			@record.trigger('apiSuccess', data)
			options.done?.apply(@record, arguments)
			return @record

	failedWithData:(options={})=>
		(error) =>
			@record.trigger('apiError', error)
			options.fail?.apply(@record, arguments)
			throw error

class Collection extends Base
	constructor: (@model) ->

	find: (id, params = {}) ->
		@request(url(new @model(id: id)), null, params).then(@recordsResponse, @failResponse)

	all: (params = {}) ->
		@request(url(@model), false, params).then(@recordsResponse, @failResponse)

	fetch: (params = {}, options = {}) ->
		delete params.id if id = params.id
		(if id then @find(id, params) else @all(params)).then((record) => @model.refresh(record, options))

	# Private
	recordsResponse : (data) =>
		@model.trigger 'apiSuccess'
		return data

	failResponse  	: (error) =>
		@model.trigger 'apiError', null, error
		throw new Error(error.message)

Include = {ajax: -> new Singleton(@)}
Extend  = {ajax: -> new Collection(@)}

Mixin =
	extended: ->
		@extend Extend
		@include Include

	# Private
	ajaxFetch: ->@ajax().fetch(arguments...)
	ajaxChange: (record, type, options = {}) ->
		return if options.ajax is false
		record.ajax()[type](options)

module.exports = Mixin
