local table = require "table"
local oo    = require "loop.base"
local HasManyAssociation = require "LuaOrm.Associations.HasManyAssociation"
local HasOneAssociation = require "LuaOrm.Associations.HasOneAssociation"
local BelongsToManyAssociation = require "LuaOrm.Associations.BelongsToManyAssociation"
local BelongsToOneAssociation = require "LuaOrm.Associations.BelongsToOneAssociation"
local HasAndBelongsToManyAssociation = require "LuaOrm.Associations.HasAndBelongsToManyAssociation"

local type = type
local ipairs = ipairs
local pairs = pairs
local print = print

--[=[
Para todas las relaciones, hay una variante (ej, hasOne y HasOne). Las que empiezan con mayúscula reciben una tabla como segundo parámetro.
NOTA: Esto de hacer una distinción por mayúsculas y minúsculas es feo, puede conducir a errores, etc. Sugerencias?
]=]

function hasOne(associatedModel, onForeignKeys, belongsToEntity)
	return HasOneAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = onForeignKeys,
		m_belongsToEntity = belongsToEntity
	}
end

function hasMany(associatedModel, onForeignKeys, belongsToEntity)
	return HasManyAssociation {
		m_associatedModelName = associatedModel,
		m_foreignKeys = onForeignKeys,
		m_belongsToEntity = belongsToEntity
	}
end

function hasAndBelongsToMany(associatedModel, onTable, onForeignKeys)
	return HasAndBelongsToManyAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = onForeignKeys,
		m_relationTable = onTable,
		isMultiple = 1
	}
end

function belongsToOne(associatedModel, onForeignKeys)
	return BelongsToOneAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = onForeignKeys
	}
end

function belongsToMany(associatedModel, onForeignKeys)
	return BelongsToManyAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = onForeignKeys,
		isMultiple = 1
	}
end



function HasOne(associatedModel, parameters)
	assert(not parameters or type(parameters) == "table", "Either nil or a table are the only valid values for 'parameters'")
	local parameters = parameters or {}
	return HasOneAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = parameters.foreignKey,
		m_belongsToEntity = (parameters.belongsToEntity == nil and true) or parameters.belongsToEntity,
		m_associatedModelAlias = parameters.alias
	}
end

function HasMany(associatedModel, parameters)
	assert(not parameters or type(parameters) == "table", "Either nil or a table are the only valid values for 'parameters'")
	local parameters = parameters or {}
	return HasManyAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = parameters.foreignKey,
		m_belongsToEntity = (parameters.belongsToEntity == nil and true) or parameters.belongsToEntity,
		m_associatedModelAlias = parameters.alias
	}
end

function HasAndBelongsToMany(associatedModel, parameters)
	assert(not parameters or type(parameters) == "table", "Either nil or a table are the only valid values for 'parameters'")
	local parameters = parameters or {}
	return HasManyAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = parameters.foreignKey,
		m_relationTable = parameters.onTable,
		isMultiple = 1,
		m_associatedModelAlias = parameters.alias
	}
end

function BelongsToOne(associatedModel, parameters)
	assert(not parameters or type(parameters) == "table", "Either nil or a table are the only valid values for 'parameters'")
	local parameters = parameters or {}
	return BelongsToOneAssociation{
		m_associatedModelName = associatedModel,
		m_foreignKeys = parameters.foreignKey,
		m_associatedModelAlias = parameters.alias
	}
end

function BelongsToMany(associatedModel, parameters)
	assert(not parameters or type(parameters) == "table", "Either nil or a table are the only valid values for 'parameters'")
	local parameters = parameters or {}
	return BelongsToManyAssociation{
		m_associatedModelName = associatedModel.associatedModel,
		m_foreignKeys = parameters.foreignKey,
		isMultiple = 1,
		m_associatedModelAlias = parameters.alias
	}
end
