local table = require "table"
local oo = require "loop.simple"
local Entity = require "LuaOrm.Entity"
local Association = require "LuaOrm.Associations.AssociationBase"
local string = require "string"

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

module("LuaOrm.Associations.HasOneAssociation")
oo.class(_M, Association)


function Validate(self, model, associatedModel)
	if (not model) then
		return nil
	end
	self.m_model = model
	if (not associatedModel) then
		return nil
	end
	self.m_associatedModel = associatedModel
	if (not self.m_foreignKeys) then
		self.m_foreignKeys = self.ResolveForeignKeys(self.m_model, self.m_associatedModel, "From")
		if (self.m_foreignKeys == nil) then
			error(string.format("Cannot define relationship without foreign keys (%s => %s)", model.tableName, associatedModel.tableName))
		end
	end
	return self
end

function GetJoinExpression(self)
	local expression = {}
	local ds = self.m_associatedModel.dataSource
	for localName, remoteName  in pairs(self.m_foreignKeys) do
		table.insert(expression, ds.Format("%Q.%Q = %Q.%Q",
			self.m_model.tableName, localName, self.m_associatedModel.tableName, remoteName
		))
	end
	return table.concat(expression, " AND ")
end

----------------------------------------------------------------
--Ties the relatedEntity to the parentEntity using the defined FK
----------------------------------------------------------------
function SetRelationshipFields(self, parentEntity, relatedEntity)
	for keyindex, keyname in pairs(self.m_model.primaryKey) do
		if (self.m_foreignKeys[keyname] ~= nil) then
			if (parentEntity[keyname] ~= nil) then
				relatedEntity[self.m_foreignKeys[keyname]] = parentEntity[keyname]
			end
		else
			error("This is technically not right!! foreign keys should always have their match...")
		end
	end
end


--in this case the query returns the one and only related entity
function BuildQuery(self, parent)
	local id = parent:GetId()
	local ds = self.m_associatedModel.dataSource
	local useNolock = ds.m_dbmsPlatform.supportsNolock and "(nolock)" or ""
	
	local query = ds.Format("SELECT DISTINCT %s FROM %Q %s, %Q %s WHERE", 
						ds:GetProjectedFields(self.m_associatedModel),
						self.m_model.tableName, useNolock,
						self.m_associatedModel.tableName, useNolock)
						
	local condition = {}
	for remoteName, localName in pairs(self.m_foreignKeys) do
		if id[remoteName] then
			table.insert(condition, ds.Format("%Q.%Q = %s", self.m_associatedModel.tableName, localName, ds:Escape(self.m_associatedModel, localName, id[remoteName])))
		end
	end
	table.insert(condition, self:GetJoinExpression())
	return query .. table.concat(condition, " AND ")
end
