---
-- xcode/xcode4_project.lua
-- Generate an Xcode project file.
-- Author Jason Perkins
-- Modified by Mihai Sebea
-- Copyright (c) 2009-2015 Jason Perkins and the Premake project
---

	local p = premake
	local m = p.modules.xcode

	local xcode = p.modules.xcode
	local project = p.project
	local config = p.config
	local fileconfig = p.fileconfig
	local tree = p.tree

--
-- Create a tree corresponding to what is shown in the Xcode project browser
-- pane, with nodes for files and folders, resources, frameworks, and products.
--
-- @param prj
--    The project being generated.
-- @returns
--    A tree, loaded with metadata, which mirrors Xcode's view of the project.
--

	function xcode.buildprjtree(prj)
		local tr = project.getsourcetree(prj, nil , false)
		tr.project = prj

		-- create a list of build configurations and assign IDs
		tr.configs = {}

		for cfg in project.eachconfig(prj) do
			cfg.xcode = {}
			cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode.name, cfg.buildcfg, "target")
			cfg.xcode.projectid = xcode.newid(tr.name, cfg.buildcfg)
			table.insert(tr.configs, cfg)
		end

        -- convert localized resources from their filesystem layout (English.lproj/MainMenu.xib)
		-- to Xcode's display layout (MainMenu.xib/English).
		 tree.traverse(tr, {
		 	onbranch = function(node)
		 		if path.getextension(node.name) == ".lproj" then
		 			local lang = path.getbasename(node.name)  -- "English", "French", etc.

		 			-- create a new language group for each file it contains
		 			for _, filenode in ipairs(node.children) do
		 				local grpnode = node.parent.children[filenode.name]
		 				if not grpnode then
		 					grpnode = tree.insert(node.parent, tree.new(filenode.name))
		 					grpnode.kind = "vgroup"
		 				end

		 				-- convert the file node to a language node and add to the group
		 				filenode.name = path.getbasename(lang)
		 				tree.insert(grpnode, filenode)
		 			end

					-- remove this directory from the tree
		 			tree.remove(node)
		 		end
		 	end
		 })

        -- the special folder "Frameworks" lists all linked frameworks
		tr.frameworks = tree.new("Frameworks")
		for cfg in project.eachconfig(prj) do
			for _, link in ipairs(config.getlinks(cfg, "system", "fullpath")) do
				local name = path.getname(link)
				if xcode.isframework(name) and not tr.frameworks.children[name] then
					node = tree.insert(tr.frameworks, tree.new(name))
					node.path = link
		 		end
		 	end
		 end

		-- only add it to the tree if there are frameworks to link
		if #tr.frameworks.children > 0 then
			tree.insert(tr, tr.frameworks)
		end

		-- the special folder "Products" holds the target produced by the project; this
		-- is populated below
		 tr.products = tree.insert(tr, tree.new("Products"))

		-- the special folder "Projects" lists sibling project dependencies
		 tr.projects = tree.new("Projects")
		 for _, dep in ipairs(project.getdependencies(prj, "sibling", "object")) do
		 	-- create a child node for the dependency's xcodeproj
		 	local xcpath = xcode.getxcodeprojname(dep)
		 	local xcnode = tree.insert(tr.projects, tree.new(path.getname(xcpath)))
		 	xcnode.path = xcpath
		 	xcnode.project = dep
		 	xcnode.productgroupid = xcode.newid(xcnode.name, "prodgrp")
		 	xcnode.productproxyid = xcode.newid(xcnode.name, "prodprox")
		 	xcnode.targetproxyid  = xcode.newid(xcnode.name, "targprox")
		 	xcnode.targetdependid = xcode.newid(xcnode.name, "targdep")

			-- create a grandchild node for the dependency's link target
		 	local lprj = premake.workspace.findproject(prj.workspace, dep.name)
		 	local cfg = project.findClosestMatch(lprj, prj.configurations[1])
		 	node = tree.insert(xcnode, tree.new(cfg.linktarget.name))
		 	node.path = cfg.linktarget.fullpath
		 	node.cfg = cfg
		end

		 if #tr.projects.children > 0 then
		 	tree.insert(tr, tr.projects)
		 end

        -- Final setup
		 tree.traverse(tr, {
		 	onnode = function(node)
		 		-- assign IDs to every node in the tree
		 		node.id = xcode.newid(node.name, nil, node.path)

		 		node.isResource = xcode.isItemResource(prj, node)

		 		-- assign build IDs to buildable files
		 		if xcode.getbuildcategory(node) then
		 			node.buildid = xcode.newid(node.name, "build", node.path)
		 		end

		 		-- remember key files that are needed elsewhere
		 		if string.endswith(node.name, "Info.plist") then
		 			tr.infoplist = node
		 		end
		 	end
		 }, true)

        -- Plug in the product node into the Products folder in the tree. The node
		-- was built in xcode.prepareWorkspace() in xcode_common.lua; it contains IDs
		-- that are necessary for inter-project dependencies
		node = tree.insert(tr.products, prj.xcode.projectnode)
		node.kind = "product"
		node.path = node.cfg.buildtarget.fullpath
		node.cfgsection = xcode.newid(node.name, "cfg")
		node.resstageid = xcode.newid(node.name, "rez")
		node.sourcesid  = xcode.newid(node.name, "src")
		node.fxstageid  = xcode.newid(node.name, "fxs")

		return tr
	end


---
-- Generate an Xcode .xcodeproj for a Premake project.
---

	m.elements.project = function(prj)
		return {
			m.header,
		}
	end

	function m.generateProject(prj)
		local tr = xcode.buildprjtree(prj)
		p.callArray(m.elements.project, prj)
		xcode.PBXBuildFile(tr)
		xcode.PBXContainerItemProxy(tr)
		xcode.PBXFileReference(tr)
		xcode.PBXFrameworksBuildPhase(tr)
		xcode.PBXGroup(tr)
		xcode.PBXNativeTarget(tr)
		xcode.PBXProject(tr)
		xcode.PBXReferenceProxy(tr)
		xcode.PBXResourcesBuildPhase(tr)
		xcode.PBXShellScriptBuildPhase(tr)
		xcode.PBXSourcesBuildPhase(tr)
		xcode.PBXTargetDependency(tr)
		xcode.PBXVariantGroup(tr)
		xcode.XCBuildConfiguration(tr)
		xcode.XCBuildConfigurationList(tr)
		xcode.footer(prj)
	end



	function m.header(prj)
		p.w('// !$*UTF8*$!')
		p.push('{')
		p.w('archiveVersion = 1;')
		p.w('classes = {')
		p.w('};')
		p.w('objectVersion = 46;')
		p.push('objects = {')
		p.w()
	end



	function xcode.footer(prj)
		p.pop('};')
		p.w('rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;')
		p.pop('}')
	end

