-- lua to hold functions for dynamic faction stuff
-- bleh
-- author: robo

-- lets define a faction save right now

-- FACTION TABLE DEFINITION
--
-- faction.name = "FACTION NAME GOES HERE" -- NAME MUST BE UNIQUE!!!
-- faction.permissions = {
--							-- FLAGS/VALUES WOULD GO IN HERE
--						 }
-- faction.inventory = {
--							-- INVENTORY JUST LIKE FOR PLAYERS
--					   }
-- faction.ranks = {
--						-- there will also be a "rank" field for each entrys data}
--					}
--

-- RANK TABLE DEFINITION
-- {
--		"title" = "TITLE OF THIS RANK"
--		"inventoryAccess" = "1" or "0" -- 1 = can remove/insert, 0 = can insert
--		"canInvite" = "1" or "0" = true or false, can invite others to faction
--		"canBoot" = "1" or "0" = true or false, can remove others from faction
--		"canPromote" = "1" or "0" = true or false, can promote others, may not promote a player higher than themselves
--		"canDemote" = "1" or "0" = true or false, can demote others of rank equal to or below them
--		"rank" = "1" for highest, bigger numbers come after in numerical order
-- }


CAKE.PlayerFactions = {};

local factionDefaults = {};

factionDefaults["name"] = "Problem loading data :(";
factionDefaults["permissions"] = {};
factionDefaults["inventory"] = {};
factionDefaults["ranks"] = {};
	
local leaderTable = {};
leaderTable["title"] = "Error leader";
leaderTable["inventoryAccess"] = "1";
leaderTable["canInvite"] = "1";
leaderTable["canBoot"] = "1";
leaderTable["canPromote"] = "1";
leaderTable["canDemote"] = "1";
leaderTable["rank"] = "1";
table.insert( factionDefaults["ranks"], leaderTable );
	
local demoRank = {};
demoRank["title"] = "Error grunt";
demoRank["inventoryAccess"] = "0";
demoRank["canInvite"] = "0";
demoRank["canBoot"] = "0";
demoRank["canPromote"] = "0";
demoRank["canDemote"] = "0";
demoRank["rank"] = "2";
table.insert( factionDefaults["ranks"], demoRank );


function CAKE.FactionExists( factionName )

	if( CAKE.PlayerFactions[factionName] != nil ) then
		return true;
	else
		return false;
	end

end

function CAKE.SaveFaction( factionName )

	local keys = util.TableToKeyValues( CAKE.PlayerFactions[factionName] );
	file.Write( "CakeScript/PlayerFactions/" .. factionName .. ".txt" , keys);

end


function CAKE.LoadFactions()

	local list = file.FindInLua( "CakeScript/PlayerFactions/*.lua" );
	
	for k, v in pairs(list) do
	
		CAKE.LoadItem(v);
		
		local Data_Raw = ""
		while ( Data_Raw == "" ) do
			Data_Raw = file.Read( "CakeScript/PlayerFactions/" .. v .. ".txt" );
		end
		
		local factionTable = util.KeyValuesToTable( Data_Raw );
		
		-- This will check and set default settings all have valid entries
		for field, default in pairs( factionDefaults ) do
		
			if( factionTable[field] == nil ) then
				Msg( "Missing faction data field '" .. tostring( field ) .. " - inserting with default value of '" .. tostring(default) .. "\n" );
				factionTable[field] = default;
			end
		
		end
		
		CAKE.PlayerFactions[v] = factionTable;
		
	end

end

-- Make sure only players who have no faction already call this.
-- Undefined behavior if used by a player who is already in a faction
function CAKE.CreateFaction( ply, factionName )

	if( string.len( factionName ) > 32 || string.len( factionName ) < 1 ) then
		CAKE.Notify(ply, "Faction name length too long. Must be less than 32 characters.");
		return;
	end

	if( file.Exists( "CakeScript/PlayerFactions/" .. factionName .. ".txt" ) ) then
		CAKE.Notify(ply, "A faction by that name already exists.");
		return;
	end
	
	local factionTable = {};
	factionTable["name"] = factionName;
	factionTable["permissions"] = {};
	factionTable["inventory"] = {};
	factionTable["ranks"] = {};
	
	local leaderTable = {};
	leaderTable["title"] = "Leader";
	leaderTable["inventoryAccess"] = "1";
	leaderTable["canInvite"] = "1";
	leaderTable["canBoot"] = "1";
	leaderTable["canPromote"] = "1";
	leaderTable["canDemote"] = "1";
	leaderTable["rank"] = "1";
	
	local demoRank = {};
	demoRank["title"] = "Recruit";
	demoRank["inventoryAccess"] = "0";
	demoRank["canInvite"] = "0";
	demoRank["canBoot"] = "0";
	demoRank["canPromote"] = "0";
	demoRank["canDemote"] = "0";
	demoRank["rank"] = "2";
	
	-- insert leader first so it has # 1
	table.insert( factionTable["ranks"], leaderTable );
	table.insert( factionTable["ranks"], demoRank );
	
	CAKE.PlayerFactions[factionName] = factionTable;

	CAKE.SaveFaction( factionName );
	
	ply:SetField( "faction", factionName, true );
	ply:SetField( "rank", "1", true );
	
	CAKE.Notify( ply, "Faction: " .. factionName .. " is formed, congradulations!" );

end

-- Make sure the player is of leader rank to disband
-- Undefined behavior if passed from a nonleader
function CAKE.DeleteFaction( ply, factionName )

	if( file.Exists( "CakeScript/PlayerFactions/" .. factionName .. ".txt" ) ) then
	
		file.Delete( "CakeScript/PlayerFactions/" .. factionName .. ".txt" );
		
		for k, v in pairs( player.GetAll() ) do
		
			CAKE.Notify(v, "Your faction has been disbanded.");
			v:SetField("faction", "", true );
			v:SetField("rank", "", true );
		
		end
		
		
	end

end

-- arg1 = item
local function FactionTakeItem( ply, cmd, args )

	if( args[1] == nil ) then
		return;
	end

	local factionName = ply:GetField("faction");
	if( !CAKE.FactionExists( factionName ) )then
		return
	end
	
	local argitem = args[ 1 ];
	local hasitem = false;

	local itemtable = ItemData[ argitem ];
	
	for k,v in pairs( (CAKE.PlayerFactions[factionName])["inventory"] ) do
	
		if( v == argitem ) then
			argitemz = k
			hasitem = true;
		end
	
	end
		
	if( hasitem ) then
		ply:GiveItem( itemtable.Class );
			
		table.remove( (CAKE.PlayerFactions[factionName])["inventory"], argitemz );
	end

	umsg.Start( "clearsearchgui", ply );
	umsg.End( );

	ply:ClearInventory();

	for k,v in pairs( (CAKE.PlayerFactions[factionName])["inventory"] ) do

		local ItemTable = ItemData[ v ];

		umsg.Start( "addsearchitem", ply )
		umsg.String( ItemTable.Model )
		umsg.Bool( ItemTable.Takeable )
		umsg.String( ItemTable.Class )
		umsg.Entity( entity )
		umsg.End( );

	end
	
	ply:RefreshInventory();
		
	ply:ConCommand("rp_factionSearch");

end
concommand.Add( "faction_takeitem", FactionTakeItem )

-- arg1 = item
local function FactionPutItem( ply, cmd, args )
	
	if( args[1] == nil ) then
		return;
	end
	
	local factionName = ply:GetField("faction");
	if( !CAKE.FactionExists( factionName ) ) then
		return
	end
	
	local item = args[ 1 ];

	local hadItem = ply:TakeItem( item );
	if( hadItem == false ) then
		return;
	end
	
	table.insert( (CAKE.PlayerFactions[factionName])["inventory"], item )

	umsg.Start( "clearsearchgui", ply ) 
	umsg.End( );
	
	ply:ClearInventory();

	for k,v in pairs( (CAKE.PlayerFactions[factionName])["inventory"] ) do

		local ItemTable = ItemData[ v ];

		umsg.Start( "addsearchitem", ply )
		umsg.String( ItemTable.Model )
		umsg.Bool( ItemTable.Takeable )
		umsg.String( ItemTable.Class )
		umsg.Entity( entity )
		umsg.End( );

    end
	
	ply:RefreshInventory();
	
	ply:ConCommand("rp_factionSearch");

end
concommand.Add( "faction_putitem", FactionPutItem );


local function factionSearch( ply, cmd, args )
	
	local factionName = ply:GetField("faction");
	if( !CAKE.FactionExists( factionName ) then
		return
	end
	
	umsg.Start( "clearsearchgui", ply )
	umsg.End( );
	
	local factionInventory = (CAKE.PlayerFactions[factionName])["inventory"]
		
	if( factionInventory == nil ) then
		(CAKE.PlayerFactions[factionName])["inventory"] = {};
		factionInventory = {};
	end
	
	for k,v in pairs( factionInventory ) do

		local ItemTable = ItemData[ v ];

		umsg.Start( "addsearchitem", ply )
		umsg.String( ItemTable.Model )
		umsg.Bool( true )
		umsg.String( ItemTable.Class )
		umsg.Entity( entity )
		umsg.String( ItemTable.Name )
		umsg.String( ItemTable.Description )
		umsg.End( );

	end

	umsg.Start( "startsearch", ply )
	umsg.String( "Faction" )
	umsg.Entity( ply )
	umsg.End( );
	
end
concommand.Add( "rp_factionSearch", factionSearch );


-- it gets called after whole file is done loading, neat huh?
CAKE.LoadFactions();