# -*- coding: utf-8 -*-
module TDiary
	#
	# class TDiaryBase
	#  tDiary CGI
	#
	class TDiaryBase
		include ERB::Util

		DIRTY_NONE = 0
		DIRTY_DIARY = 1
		DIRTY_COMMENT = 2
		DIRTY_REFERER = 4

		attr_reader :cookies, :date, :diaries
		attr_reader :cgi, :rhtml, :conf
		attr_reader :ignore_parser_cache

		def initialize( cgi, rhtml, conf )
			@cgi, @rhtml, @conf = cgi, rhtml, conf
			@diaries = {}
			@cookies = []
			@io = @conf.io_class.new( self )
			@ignore_parser_cache = false
		end

		def eval_rhtml( prefix = '' )
			begin
				r = do_eval_rhtml( prefix )
			rescue PluginError, SyntaxError, ArgumentError
				r = ERB.new(File.read("#{PATH}/skel/plugin_error.rhtml").untaint).result(binding)
			rescue Exception
				raise
			end
			r
		end

		def last_modified
			nil
		end

		def []( date )
			@diaries[date.strftime( '%Y%m%d' )]
		end

		def calendar
			@years = @io.calendar unless @years
		end

	protected

		def do_eval_rhtml( prefix )
			load_plugins

			r = @io.restore_cache( prefix )

			if r.nil?
				r = @rhtml ? erb_src(prefix) : ""
				@io.store_cache( r, prefix ) unless @diaries.empty?
			end

			r = @plugin.eval_src( r.untaint, @conf.secure ) if @plugin

			@cookies += @plugin.cookies

			r
		end

		def mode
			self.class.to_s.sub( /^TDiary::TDiary/, '' ).downcase
		end

		def load_plugins
			calendar
			#
			# caching plugin
			# NOTE: currently, plugin cache doesn't work with blog-category plugin
			#       see also https://github.com/tdiary/tdiary-core/issues/203
			#
			if @plugin and not @plugin.respond_to?( 'blog_category' )
				@plugin.diaries = @diaries
				@plugin.date = @date
				@plugin.last_modified = last_modified
				@plugin.comment = @comment
				@plugin
			else
				@plugin = Plugin::new(
					'conf' => @conf,
					'mode' => mode,
					'diaries' => @diaries,
					'cgi' => @cgi,
					'years' => @years,
					'cache_path' => @io.cache_path,
					'date' => @date,
					'comment' => @comment,
					'last_modified' => last_modified,
					'logger' => TDiary.logger
				)
			end
		end

		def <<( diary )
			@diaries[diary.date.strftime( '%Y%m%d' )] = diary
		end

		def delete( date )
			@diaries.delete( date.strftime( '%Y%m%d' ) )
		end

	private

		def erb_src(prefix)
			rhtml = ["header.rhtml", @rhtml, "footer.rhtml"].map do |file|
				path = "#{PATH}/skel/#{prefix}#{file}"
				begin
					File.read("#{path}.#{@conf.lang}")
				rescue
					File.read(path)
				end
			end.join

			begin
				r = ERB.new(rhtml.untaint).result(binding)
			rescue => e
				# migration error on ruby 1.9 only 1st time, reload.
				if defined?(::Encoding) && e.class == ::Encoding::CompatibilityError
					raise ForceRedirect.new(@conf.base_url)
				end
			end
			ERB.new(r).src
		end
	end

	#
	# class TDiaryCategoryView
	#  base of category view mode classes
	#
	class TDiaryCategoryView < TDiaryBase
		attr_reader :last_modified

		def initialize(cgi, rhtml, conf)
			super
			@last_modified = Time.now
		end
	end

	#
	# class TDiarySearch
	#  base of search view mode classes
	#
	class TDiarySearch < TDiaryBase
		attr_reader :last_modified

		def initialize(cgi, rhtml, conf)
			super
			@last_modified = Time.now
		end
	end

	# class TDiaryPluginView
	#  base of plugin view mode classes
	#
	class TDiaryPluginView < TDiaryBase
		attr_reader :last_modified

		def initialize(cgi, rhtml, conf)
			super

			tdiary = tdiary_class(cgi.params['date'][0] || '').new(cgi, '', conf)
			@date = tdiary.date
			@diaries = tdiary.diaries
			@last_modified = Time.now
		end

		def eval_rhtml( prefix = '' )
			load_plugins
			# TODO: prefixでモバイルモードかどうかを判定
			# TODO: rhtml rendering
			@rhtml = "#{plugin_name}.rhtml"
			@plugin.__send__(:content_proc, plugin_name, @date.strftime('%Y%m%d'))
		end

		protected

		def plugin_name
			# plugin name MUST contain only words ([a-zA-Z0-9_])
			@plugin_name ||= (@cgi.params['plugin'][0] || '').match(/^(\w+)$/).to_a[1]
			raise TDiary::PermissionError.new('invalid plugin name') unless @plugin_name
			@plugin_name
		end

		def tdiary_class(date)
			# YYYYMMDD-N, YYYYMMDD, YYYYMM, MMDD, or nil
			case date
			when /^\d{8}-\d+$/
				TDiaryLatest
			when /^\d{8}$/
				TDiaryDay
			when /^\d{6}$/
				TDiaryMonth
			when /^\d{4}$/
				TDiaryNYear
			else
				TDiaryLatest
			end
		end
	end
end

# Local Variables:
# mode: ruby
# indent-tabs-mode: t
# tab-width: 3
# ruby-indent-level: 3
# End:
# vim: ts=3
