#Minimalistic gui framework for wxruby
#Author: Nicolas Guzzo
require "wx"
require 'singleton'
#TODO: config class and load from yaml file if one present
#TODO: add logger
MODELSDIR="models/"
CONTROLLERSDIR="controllers/"
HELPERSDIR="helpers/"
VIEWSDIR="views/"

module Ybur
	class Ybur	
		include Singleton
		@@controllers=[]
		@@models=[]		
		def Ybur.get_controllers
			@@controllers
		end
		def initialize	
		end
		def init
			#Load Models
			if File.exist?(MODELSDIR) and File.directory?(MODELSDIR)
				c = Dir.new(MODELSDIR)
				c.each  do |x| 
					if x =~ /^\w+.rb$/
						require MODELSDIR+x
					end	
				end
			end
			#Load Helpers
			if File.exist?(HELPERSDIR) and File.directory?(HELPERSDIR)
				c = Dir.new(HELPERSDIR)
				c.each  do |x|
					if x =~ /^\w+.rb$/
						require HELPERSDIR+x						
					end	
				end			
			end
			#Load Controllers
			if File.exist?(CONTROLLERSDIR) and File.directory?(CONTROLLERSDIR)
				c = Dir.new(CONTROLLERSDIR)
				c.each  do |x|
					if x =~ /^\w+.rb$/
						require CONTROLLERSDIR+x
						controller_name=x.scan(/^(\w+).rb$/)
						if !controller_name.empty? and !controller_name[0].empty?
							name=controller_name[0][0]
							@@controllers<<name
						end
					end	
				end			
			end
			yield if block_given?
			MainApp.new.main_loop
		end
	end
	class Vars
		@@vars={}		
		def Vars.store(k,o)
			@@vars[k]=o
		end
		def Vars.pass(k,o)
			#p "passing "+ @@vars[k].instance_variables.to_s
			@@vars[k].instance_variables.each do |d|
				v=nil
				@@vars[k].instance_eval "v=#{d}"
				o.instance_eval "#{d}=v"
			end
		end		
	end
	class View < Wx::Panel
		@@views={}
		@@tmp_parent=nil
		@@tmp_view_name=""
		def initialize parent=nil
			if !parent
				super @@tmp_parent
			end
			@@views[@@tmp_view_name]=self
			Vars.pass(@@tmp_view_name,self)
		end
		def create &block
			self.instance_eval(&block)
		end
		def View.partial &block						
			v=@@views[@@tmp_view_name]
			Vars.pass(@@tmp_view_name,v)
			v.instance_eval(&block)
		end
		def link_to route,params={}
			Ybur.router route,params
		end
		def View.get_view name
			return @@views[name]
		end
		def View.set_current_view name
			@@tmp_view_name=name
		end
		def View.set_view_parent p
			@@tmp_parent=p
		end
	end
	class Controller		
		@@controllers={}
		@@shown_views={}		
		def initialize
			name=myname
			if name!=""
				@@controllers[name]=self
				#p "controller: "+name
			end
		end
		def Controller.get_by_name name
			return @@controllers[name]
		end		
		def render parent,params={}
			if params[:force_render]
				force_render=params[:force_render]
			else
				force_render=false
			end			
			if params[:controller]
				controller_name=params[:controller].to_s
			else
				controller_name= myname.downcase
			end
			if params[:view]
				view_name=params[:view].to_s
			else
				view_name=caller(1).first.scan(/^(.+?):(\d+)(?::in `(.*)')?/)[0][2].to_s				
			end			
						
			if params[:partial]
				#p "partial"
				if params[:dest_view]
					dest_view=params[:dest_view]
				else
					#p "must specify destination view for partial"
					return nil
				end
				view_name="_"+view_name				
				force_render=true				
				parent=View.get_view(controller_name+dest_view.to_s)
				View.set_current_view(controller_name+dest_view.to_s)
			else
				View.set_current_view(controller_name+view_name)
			end
			
			vname=controller_name+view_name
			View.set_view_parent(parent)
			
			#p "render: "+vname+"!!!"
			@@shown_views[vname] ||=false
			if !@@shown_views[vname] or force_render				
				file=VIEWSDIR+controller_name+"/"+view_name+".rb"
				if File.exist?(file)
					Vars.store(vname,self)
					load file
					@@shown_views[vname]=true	
				else
					#p "no such file: "+file				
				end
			else
				#p name+" already shown!!!"			
			end
			#returns view so it can be used from a layout
			return View.get_view vname
		end
		private
		def myname
			self.class.name
		end
	end
	def Ybur.router route,params={}
		r=route.split('/')
		name=r[1]
		m=r[2]
		controller=Controller.get_by_name name.capitalize
		if params!={}
			controller.send m,params
		else
			controller.send m
		end
	end
	class Layout < Wx::Panel
		@@layouts={}
		def initialize name			
			@@layouts[name]=self
			super $tmp_main_layout
		end
		def Layout.[](name)			
			@@layouts[name]			
		end
		def link_to route,params={}
			Ybur.router route,params
		end
		##executes a controller action
		def action parent, route
			r=route.split('/')
			name=r[1]
			m=r[2]
			w=nil
			#p "action: "+route
			controller=Controller.get_by_name(name.capitalize)
			if controller
				w=controller.send m, parent
			end
			return w
		end
	end
	class MainWindow < Wx::Frame
		def initialize params={}
			super(nil,params)			
		end
		def link_to route,params={}
			Ybur.router route,params
		end
		def controller parent,name
			$tmp_main_layout=parent
			controller=nil
			eval("controller="+name.to_s.capitalize+".new")
			if controller
				#layout
				file=VIEWSDIR+name.to_s+"/layout.rb"
				if File.exist?(file)
					load file
				end
				if controller.respond_to? :index
					controller.index
				end
			end
			Layout[name]
		end
		def create &block
			self.instance_eval(&block)
			send_size_event
			show()
		end
	end
	class MainApp < Wx::App
		def on_init			
			#MainWindow.new()
			file=VIEWSDIR+"/main_window.rb"
			if File.exist?(file)
				load file
			end
			#p "app loaded!!!"
		end
	end
end 
