#! /usr/bin/env ruby


# == Synopsis
# 
# A simple commandline tool for basic site management
# 
# == Usage
#    
#  yurt newsite  foldername [port] <- creates a new directory structure for a 
#                                     Yurt CMS site, with a preconfigured 
#                                     apache conf file
#  yurt newfile    path/to/file   <- creates a new content file
#  yurt update     [path/to/file] <- updates yurt infrastructure to latest 
#                                    version. path/to/file is optional if you're
#                                    in the top level directory of your yurt 
#                                    install
#  yurt newpartial path/to/file   <- creates a new partial content file
#  yurt generate   path/to/file   <- generates html from supplied content file
#  yurt delete     path/to/file   <- deletes content file and html files
# 
# == Author
# 
# Robert Hahn <yurt_at_roberthahn_dot_ca>
# 
# == Copyright
# 
# Copyright (c)2006 Robert Hahn.  Licensed under the same terms as the Camping framework
# 

require File.dirname( __FILE__ ) + "/../lib/yurtcms"
require 'rdoc/usage'
require 'rbconfig.rb'
include Config

# this is needed to support the generate() function
class Hash
	def method_missing(methID)
		self[methID.id2name]
	end
end



def newsite yurt_root, port
	# create directory
	Dir.mkdir yurt_root

	# copy template from CONFIG["datadir"]/yurt/dir_template.zip
	source_files = Dir.glob( File.dirname( __FILE__ ) + "/../site/**/*" )

	source_files.each do |sf|
		local_f = [ yurt_root, sf.gsub( /^.*?site\//, "" ) ].join( "/" )
		case File.stat( sf ).ftype
		when "directory"
			Dir.mkdir local_f
			File.chmod( 0777, local_f )
		when "file"
			source = File.read( sf )

			# if the file we read in is yurt.conf, we need to modify it to point to the web root.
			if File.basename( sf ) == "yurt.conf"
				source.gsub!( /<%= port %>/, port )
				source.gsub!( /<%= yurt_root %>/, yurt_root )
				local_f.gsub!( /yurt\.conf/, File.basename( yurt_root ) + ".conf" )
			end

			writefile( source,local_f )
		end
	end

	# write out a preferences file

	writefile( "yurt_root: " + yurt_root, yurt_root + "/yurt.prefs" )
end
	
def update yurt_root

	# copy template from CONFIG["datadir"]/yurt/dir_template.zip
	source_files = Dir.glob( File.dirname( __FILE__ ) + "/../site/yurt/**/*" )

	source_files.each do |sf|
		local_f = [ yurt_root, sf.gsub( /^.*?site\//, "" ) ].join( "/" )
		case File.stat( sf ).ftype
		when "directory"
			begin
				Dir.mkdir local_f
			rescue SystemCallError => e
				unless e.errno == Errno::EEXIST::Errno
					exit
				end
			end
			File.chmod( 0777, local_f )
		when "file"
			source = File.read( sf )
			writefile( source,local_f )
		end
	end
end

def writefile sf_str, df
	File.open( df, "w" ) do |dest|
		dest.puts sf_str
	end
	File.chmod( 0777, df )
end

def normalize_path path
	# This wasn't something that could easily be done, as I realized there was 
	# a number of situations that could legitimately occur.   The following comment
	# block will describe the logic required:
	#
	# 1. Is the supplied #{ path } absolute (begins with "/")?
	#
	# - if 1., then test 2.
	# - if not 1., compute final path by concatenating cwd to #{ path }, call it 
	# 	full_path, then test 2.

	if path[0,1] != "/"
		# it's a relative path
		path = [ Dir.getwd, path ].join( "/" )
	end

	# 2. Can I chdir to full_path?
	#
	# - If 2., getwd, then use it to locate yurt.prefs, then test 3.
	# - If not 2, raise an error (destination not valid)
	
	begin
		Dir.chdir( File.dirname( path ) )
		path = [ Dir.getwd, File.basename( path ) ].join( "/" )
	rescue Exception => e
		puts e.message
		exit 1
	end

	# The following yield statement allows for implementation-specific tests to 
	# validate the path
	yield path if block_given?

	return path
end

def find_yurt_pref full_path
	fp = full_path
	yurt_root = nil
	if File.exists? [ fp, "yurt.prefs" ].join( "/" )
		yurt_root = fp
	else
		puts fp
		while fp.include? "/content"
			fp = fp.gsub( /content\/.*?$/, "" )
			if File.exists? [ fp, "yurt.prefs" ].join( "/" )
				yurt_root = fp
				break
			end
		end
	end

	return yurt_root
end

def newfile path
	# create file
	File.open( path, "w" ) do |f|
		f.puts "---"
		f.puts "template: template.html"
		f.puts "title: enter page title"
		f.puts "description: enter page meta description content"
		f.puts "keywords: enter keywords here"
		f.puts "content: |-"
		f.puts "  Enter your content here. Please ensure that you begin each new line with two spaces while in this area."
	end
	File.chmod( 0777, path )
end

def newpartial path
	# create file
	File.open( path, "w" ) do |f|
		f.puts "---"
		f.puts "partial: yes"
		f.puts "content: |-"
		f.puts "  Enter your content here. Please ensure that you begin each new line with two spaces while in this area."
	end
	File.chmod( 0777, path )
end

def get_yurt_path_pieces path
	path = normalize_path path do |p|
		# Is the computed path in #{ yurt_root }/content, and does a yurt.prefs file exist?
		unless ( p.include? "/content" ) && find_yurt_pref( p )
			puts "Not a valid yurt CMS web path - the file must be in /content, and a yurt.prefs file must be present."
			exit 1
		end
		# are we about to generate a file?
		#unless File.exists?( p ) && File.ftype( p ) == "file"
		#	puts "Not a valid yurt CMS file.  If you need to generate a file, please check your path."
		#	exit 1
		#end
	end

	yurt_root = find_yurt_pref( path )

	file_to_generate = path
	file_to_generate[ yurt_root + "content/" ] = ''
	return [ yurt_root, file_to_generate ]
end

def generate yurt_root, file_to_generate
	y = YurtCMS.new( yurt_root )

	y.write_all_files( y.get_file_metadata( file_to_generate ) )
end

def delete yurt_root, file_to_generate
	y = YurtCMS.new( yurt_root )
	y.delete( file_to_generate )
end

def mkdir yurt_root, file_to_generate
	y = YurtCMS.new( yurt_root )
	y.make_new_dir( File.dirname( file_to_generate ), File.basename( file_to_generate ) )
end

case
when ARGV[0] == "newsite"
	# check for and collect folder name
	yurt_root = normalize_path ARGV[ 1 ]

	port = "9878"
	port = ARGV[ 2 ] if ARGV[ 2 ] && ARGV[ 2 ].match( /^\d*$/ )

	newsite( yurt_root, port )
when ARGV[0] == "update"
	if ARGV[ 1 ]
		yurt_root = find_yurt_pref ARGV[ 1 ]
	else
		yurt_root = find_yurt_pref Dir.getwd
	end
	update yurt_root
when ARGV[0] == "newfile"
	# check for a path/to/file
	path = normalize_path ARGV[ 1 ] do |p|
		# Is the computed path in #{ yurt_root }/content, and does a yurt.prefs file exist?
		unless ( p.include? "/content" ) && find_yurt_pref( p )
			puts "Not a valid yurt CMS web path - the file must be in /content, and a yurt.prefs file must be present."
			exit 1
		end
	end

	newfile( path )
when ARGV[0] == "newpartial"
	# check for a path/to/file
	path = normalize_path ARGV[ 1 ] do |p|
		# Is the computed path in #{ yurt_root }/content, and does a yurt.prefs file exist?
		unless ( p.include? "/content" ) && find_yurt_pref( p )
			puts "Not a valid yurt CMS web path - the file must be in /content, and a yurt.prefs file must be present."
			exit 1
		end
	end

	newpartial( path )
when ARGV[0] == "generate"
	# check for a path/to/file
	yurt_root, file_to_generate = get_yurt_path_pieces( ARGV[1] )

	generate( yurt_root, file_to_generate )
when ARGV[0] == "mkdir"
	# check for a path/to/file
	yurt_root, file_to_generate = get_yurt_path_pieces( ARGV[1] )

	mkdir( yurt_root, file_to_generate )
when ARGV[0] == "delete"
	# check for a path/to/file
	yurt_root, file_to_generate = get_yurt_path_pieces( ARGV[1] )

	delete( yurt_root, file_to_generate )
else
	RDoc::usage
end


