begin
	require 'sketchup' # First we pull in the standard API hooks.
	require 'ShaDe//lib//utils.rb'
	require 'ShaDe//lib//geometry.rb'
	require 'ShaDe//lib//data-structures.rb'
	require 'ShaDe//lib//constraints.rb'
	require 'ShaDe//lib//goals.rb'
rescue LoadError
	require "#{File.dirname(__FILE__)}/utils"
	require "#{File.dirname(__FILE__)}/geometry"
	require "#{File.dirname(__FILE__)}/data-structures"
	require "#{File.dirname(__FILE__)}/constraints"
	require "#{File.dirname(__FILE__)}/goals"
end


#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#This class represents a rule
class Rule
	
	#Internal rule ID
	attr_accessor :rule_id
	
	#The left labelled shape
	attr_accessor :alpha
	#The right labelled shape
	attr_accessor :beta
	#The difference left - right shape
	attr_accessor :alpha_minus_beta
	#The difference right - left shape
	attr_accessor :beta_minus_alpha
	
	#Hashes of groups (one for each layer)
	attr_accessor :line_group
	attr_accessor :arrow_group
	attr_accessor :group_origin_left
	attr_accessor :group_origin_right
	
	attr_accessor :line_group_component
	attr_accessor :arrow_group_component
	attr_accessor :group_origin_left_component
	attr_accessor :group_origin_right_component
	
	#rule_id: internal id for the rule
	#alpha: the left RuleLabelledShape
	#beta: the right RuleLabelledShape
	#
	#Initializes the rule
	def initialize(rule_id, alpha, beta, line_group, arrow_group, group_origin_left, group_origin_right)
		
		@rule_id = rule_id
		
		@alpha = alpha
		@alpha.host_rule_id = rule_id
		@alpha.host_rule_part = Constants::LEFT
		
		@beta = beta
		@beta.host_rule_id = rule_id
		@beta.host_rule_part = Constants::RIGHT

		
		@line_group = line_group
		@arrow_group = arrow_group
		@group_origin_left = group_origin_left
		@group_origin_right = group_origin_right
		
	end
	
	#returns:: the left shape of the rule
	def left
		return @alpha
	end
	
	#returns:: the right shape of the rule
	def right
		return @beta
	end
	
	#Repaints the rule
	def repaint
		if Shade.using_sketchup
			@alpha.paint
			@beta.paint
			
			entities = Sketchup.active_model.entities

			t = Shade.project.execution.grammar.get_rule_index(self)

			# Transform the layout transformation of the origins
			t_left = Geom::Transformation.new
			t_right = Geom::Transformation.new
			t.times do
				t_left = Constants::DESCEND_T * t_left
				t_right = Constants::DESCEND_T * t_right
			end
			t_left = Constants::LEFT_T * t_left
			t_right = Constants::RIGHT_T * t_right

			# Draw an arrow, for the rule
			point1 = Constants::PTS_ARROW[0].clone
			point2 = Constants::PTS_ARROW[1].clone
			point3 = Constants::PTS_ARROW[2].clone
			point4 = Constants::PTS_ARROW[3].clone
			
			t.times do
				point1.transform! Constants::DESCEND_T 
				point2.transform! Constants::DESCEND_T 
				point3.transform! Constants::DESCEND_T 
				point4.transform! Constants::DESCEND_T 
			end

			@arrow_group = entities.add_group
			@arrow_group.entities.add_edges point1, point2
			@arrow_group.entities.add_edges point3, point2
			@arrow_group.entities.add_edges point4, point2
			@arrow_group.locked = true
			
			#Draw the origin references
			point1 = Constants::PTS_ORIGIN[0].clone
			point2 = Constants::PTS_ORIGIN[1].clone
			point3 = Constants::PTS_ORIGIN[2].clone
			point4 = Constants::PTS_ORIGIN[3].clone
			
			@group_origin_left = entities.add_group
			@group_origin_left.entities.add_edges point1, point3
			@group_origin_left.entities.add_edges point2, point4
			@group_origin_left.transformation = t_left
			@group_origin_left.locked = true
			
			@group_origin_right = entities.add_group
			@group_origin_right.entities.add_edges point1, point3
			@group_origin_right.entities.add_edges point2, point4
			@group_origin_right.transformation = t_right
			@group_origin_right.locked = true
			
			#Draw horizontal line
			point_h1 = Constants::PTS_H[0].clone
			point_h2 = Constants::PTS_H[1].clone
			
			t.times do
				point_h1.transform! Constants::DESCEND_T 
				point_h2.transform! Constants::DESCEND_T 
			end
			@line_group = entities.add_group
			@line_group.entities.add_line point_h1,point_h2
			@line_group.locked = true
		end
	end	
	
	#returns:: the resulting shape of making the difference: alpha - beta (left and right shapes, respectively)
	def alpha_minus_beta		
		alpha_minus_beta = @alpha.clone
		alpha_minus_beta.shape_expression(@beta, Constants::DIFFERENCE, Constants::SEGMENTS)
		alpha_minus_beta.shape_expression(@beta, Constants::DIFFERENCE, Constants::POINTS)
		return alpha_minus_beta
	end
	
	#returns:: the resulting shape of making the difference: beta - alpha (right and left shapes, respectively)
	def beta_minus_alpha
		
		beta_minus_alpha = @beta.clone
		beta_minus_alpha.shape_expression(@alpha, Constants::DIFFERENCE, Constants::SEGMENTS)
		beta_minus_alpha.shape_expression(@alpha, Constants::DIFFERENCE, Constants::POINTS)
		return beta_minus_alpha
	end
	
	#Erases the SU objects attached to the rule
	def erase()
		if Shade.using_sketchup
			entities = Sketchup.active_model.entities
			
			Sketchup.active_model.layers.each { |layer|
				
				if @arrow_group
					if @arrow_group[layer.name]
						@arrow_group[layer.name].locked = false
						entities.erase_entities @arrow_group[layer.name]
					end
				end
					
				if @line_group
					if @line_group[layer.name]
						@line_group[layer.name].locked = false
						entities.erase_entities @line_group[layer.name]
					end
				end
					
				if @group_origin_left
					if @group_origin_left[layer.name]
						@group_origin_left[layer.name].locked = false
						entities.erase_entities @group_origin_left[layer.name]
					end
				end
					
				if @group_origin_right
					if @group_origin_right[layer.name]
						@group_origin_right[layer.name].locked = false
						entities.erase_entities @group_origin_right[layer.name]
					end
				end
			}
			
			@alpha.erase
			@beta.erase
		end
	end
	
end

#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#Abstract representation of a grammar, that is, a set of rules
class Grammar
	#Array for the rules
	attr_reader :rules
	
	#The axiom LabelledShape
	attr_reader :axiom
	
	#True iff the grammar has been saved
	attr_accessor :saved
	
	#Initializing
	def initialize()
		@rules = Array.new
		@saved = true
	end
	
	#rule:: a Rule object to add
	#
	#Adds a rule to the grammar
	def add_rule(rule)
		@rules.push(rule)
	end
	
	#i:: index of the rule to remove
	#
	#Removes the rule in the grammar with the index i
	def remove_rule(i)
		rule = @rules[i]
		rule.erase
		#Delete from the array
		@rules.delete_at(i)
	end
	
	#shape:: a LabelledShape that will be the axiom of the grammar
	#
	#Sets the axiom to the specified shape
	def axiom=(shape)
		@axiom = shape
	end	
	
	#rule:: a Rule object, representing one of the grammar rules
	#
	#returns:: the index of the rule (not the ID)
	def get_rule_index(rule)
		result = nil
		i = 0
		while ((i < @rules.size) && !result)
			if @rules[i].rule_id == rule.rule_id
				result = i
			end
			i+=1
		end
		return result
	end
	
	#rule_id:: an id
	#
	#returns the rule with the internal id rule_id. In case it does not exist, returns nil
	def search_rule_by_id(rule_id)
		i = 0
		found = false
		size = @rules.size
		rule = nil
		
		while i < size and !found
			if @rules[i].rule_id == rule_id
				rule = @rules[i]
				found = true
			end
			i +=1
		end
		return rule
	end
	
	#shape_id:: an id
	#
	#returns the shape with the internal id shape_id. In case it does not exist, returns nil
	def search_shape_by_id(shape_id)
		i = 0
		found = false
		size = @rules.size
		shape = nil
		
		while i < size and !found
			if @rules[i].left.shape_id == shape_id
				shape = @rules[i].left
				found = true
			elsif @rules[i].right.shape_id == shape_id
				shape = @rules[i].right
				found = true
			end
			i +=1
		end
		return shape	
	end

	#path:: the path to save the shape in
	#
	#Saves the shape in the specified path
	def save(path, text = false)
		#the path is a .gr2 file
		#we need the directory
		directory = ShadeUtils.get_directory_from_path(path)
		title = ShadeUtils.get_title_from_path(path)
		
		if text
			extension = "txt"
		else
			extension = "skp"
		end
		
		File.open(path.strip, 'w') do |f|
			@rules.each { |rule|
				f.write("alpha#{rule.rule_id}#{title}.#{extension} beta#{rule.rule_id}#{title}.#{extension}\n")
				rule.alpha.save("#{directory}alpha#{rule.rule_id}#{title}.#{extension}")
				rule.beta.save("#{directory}beta#{rule.rule_id}#{title}.#{extension}")
			}
			if Shade.project.execution.file_axiom
				f.write("AXIOM: axiom#{title}.#{extension}\n")
				@axiom.save("#{directory}axiom#{title}.#{extension}")
			end
		end
		
		
	end
	
	#path:: the path to load the shape from
	#
	#Loads the shape from the specified path
	def load(path)
		
		#the path is a .gr2 file
		#we need the directory
		directory = ShadeUtils.get_directory_from_path(path)
		
		size = @rules.size
		i = 0
		while i < size
			remove_rule(size-i-1)
			i += 1
		end
		@rules = Array.new
		
    Shade.project.execution.file_axiom = false
    
		filename = path.strip
		
		File.open(filename, 'r') do |f|
			while line = f.gets
				line_a = line.split
				if line_a[0] == "AXIOM:"
					Shade.project.execution.file_axiom = true
					@axiom = LabelledShape.new(Array.new, Array.new)
					@axiom.load("#{directory}#{line_a[1]}")
				else
					alpha_title = line_a[0]
					beta_title = line_a[1]
					alpha = RuleLabelledShape.new(Array.new, Array.new, nil, nil)
					alpha.load("#{directory}#{alpha_title}")
					
					beta = RuleLabelledShape.new(Array.new, Array.new, nil, nil)
					beta.load("#{directory}#{beta_title}")
					if @rules.empty?
						last_id = 0
					else
						last_id = @rules.last.rule_id
					end
					rule = ShadeUtils.paint_rule(last_id+1, alpha, beta)
					@rules.push rule
				end		
			end
		end
		
		if !Shade.project.execution.file_axiom
			new_axiom = LabelledShape.new(Array.new, Array.new)
			@rules[0].left.p.each_key {|layer_name|
				new_axiom.p[layer_name] = @rules[0].left.p[layer_name].clone
			}
			@rules[0].left.s.each_key {|layer_name|
				new_axiom.s[layer_name] = @rules[0].left.s[layer_name].clone
			}
			Shade.project.execution.grammar.axiom = new_axiom
		end
		
		Shade.project.execution.reset
	end
end
	
#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#This class gathers the current grammar, constraints and goals in order to execute them (with Krishnamurti algorithms) and produce designs
class Execution
	#A Grammar object
	attr_accessor :grammar
	
	#A CurrentLabelledShape object (the current design)
	attr_accessor :current_shape
	
	#True if we want the labels to appear in the current shape
	attr_accessor :show_labels
	
  #True if we want the black labels to appear in the current shape
  attr_accessor :hide_black
	
	#An array of pairs [rule_id, transformation] applied to the axiom, in order of application
	attr_accessor :execution_history
	
	attr_accessor :file_axiom
	
	attr_accessor :backtracking_steps
	attr_accessor :show_backtracking_steps
	
	#An array of Constraint objects
	attr_accessor :constraints
	#An array of Goals objects
	attr_accessor :goals
	
	#Timeout seconds for the backtracking algorithm
	#If nil or 0, then no timeout will be considered
	attr_reader :timeout
	
	#True if the timeout has been reached
	attr_accessor :timeout_reached
	
	#Time when the last backtracking process started
	attr_reader :beginning_time
	
	#grammar:: the grammar to apply
	#current_shape:: shape in which to store the design
	def initialize(grammar, current_shape)
		@grammar= grammar
		@current_shape = current_shape
		@show_labels = true
    @hide_black = false
		@execution_history = Array.new
		@file_axiom = false
		@backtracking_steps = 0
		@show_backtracking_steps = false
		@constraints = Array.new
		@goals = Array.new
		
		@timeout = nil
		@timeout_reached = false
		@beginning_time = 0
	end
	
	#directory:: the directory to save the execution history in
	#
	#Saves the execution history (that is, the sequence of applied rules and the produced shape in each step) into the specified directory
	def save_execution_history(directory)
		if @execution_history
			if @execution_history.size > 0
				if File.exist? "#{directory}\\entries.txt"
					File.delete("#{directory}\\entries.txt")
				end
				File.open("#{directory}\\entries.txt", 'w') do |f|
			
					execution_history.each{ |entry|
						t_string = nil
						entry[1].each { |e|
							if t_string
								t_string = "#{t_string},#{e}"
							else
								t_string = "#{e}"
							end
						}
						#puts t_string
						f.write "#{entry[0]},#{t_string}\n"
					}
				
				end
				execution_history.each_with_index{ |entry, i|
					entry[2].save("#{directory}\\shape#{i}.txt")
				}
			end
		end
	end
	
	#directory:: the directory to load the execution history from
	#
	#Loads the execution history (that is, the sequence of applied rules and the produced shape in each step) from the specified directory
	def load_execution_history(directory)
		@execution_history = Array.new
		if File.exist? "#{directory}\\entries.txt"
			j = 0
			File.open("#{directory}\\entries.txt", 'r') do |f|
				while (line = f.gets)
					line_a = line.split(",")
					
					if line_a.size > 1
						rule_id = line_a[0].to_i
						t = Array.new(6)
						for i in 1..6
							t[i-1] = line_a[i].to_f
						end
						
						shape = CurrentLabelledShape.new([], [])
						shape.load("#{directory}\\shape#{j}.txt")
						
						@execution_history.push [rule_id, t, shape]
						j += 1
					end
				end
			end
		end
	end
	
	#Constraint:: A Constraint object to add
	#return:: true iff the Constraint was not added yet
	#
	#Adds a Constraint to the project
	def add_constraint(constraint)
		name = constraint.name
		found = false
		i = 0
		size = @constraints.length
		while i < size && !found
			if @constraints[i].name == name
				found = true
			end
			i+=1
		end
		if !found   
			@constraints.push constraint
			Shade.project.saved = false
		end
		return !found
	end
	
	#Goal:: A Goal object to add
	#return:: true iff the Goal was not added yet
	#
	#Adds a Goal to the project
	def add_goal(goal)
		name = goal.name
		found = false
		i = 0
		size = @goals.length
		while i < size && !found
			if @goals[i].name == name
				found = true
			end
			i+=1
		end
		if !found   
			@goals.push goal
			Shade.project.saved = false
		end
		
		return !found
	end
	
	#name: name of the Constraint to delete
	#return:: true if the Constraint had been added previously
	#
	#Deletes the Constraint whose name is equal to name
	def delete_constraint(name)
		found = false
		i = 0
		size = @constraints.length
		while i < size && !found
			if @constraints[i].name == name
				found = true
				constraint = @constraints[i]
				constraint.delete()
				@constraints.delete_at(i)
			end
			i+=1
		end
	 
		if found 
			Shade.project.saved = false
		end
		return found
	end
	
	#name: name of the goal to delete
	#return:: true if the goal had been added previously
	#
	#Deletes the goal whose name is equal to name
	def delete_goal(name)
		found = false
		i = 0
		size = @goals.length
		while i < size && !found
			if @goals[i].name == name
				found = true
				goal = @goals[i]
				goal.delete()
				@goals.delete_at(i)
			end
			i+=1
		end
	 
		if found 
			Shade.project.saved = false
		end
		return found
	end
	
	#name:: a constraint name
	#
	#Gets the Constraint object responding to name
	def get_constraint(name)
		found = false
		constraint = nil
		i = 0
		size = @constraints.length
		while i < size && !found
			if  @constraints[i].name == name
				found = true
				constraint =  @constraints[i]
			end
			i+=1
		end
		return constraint
	end
	
	#name:: a goal name
	#
	#Gets the Goal object responding to name
	def get_goal(name)
		found = false
		goal = nil
		i = 0
		size = @goals.length
		while i < size && !found
			if  @goals[i].name == name
				found = true
				goal =  @goals[i]
			end
			i+=1
		end
		return goal
	end
	
	#Prints the applied transformations in the ruby console
	def print_transformations
		@execution_history.each { |triple|
			puts triple[1]
			puts "--"
		}
		return nil
	end
	
	
	#A step of Krishnamurti algorithm
	def step_1_2_dist_points(rule, dp_alpha, map, f, dptr, k, layer_name)
		k += 1
	    if !@current_shape.pi[layer_name]
	      @current_shape.create_pi
	    end
		#if @current_shape.pi[layer_name]
			if @current_shape.pi[layer_name].get_node_i(k)
				pik = @current_shape.pi[layer_name].get_node_i(k).list #The index of the kth largest set of labelled points in the current shape
				#puts "k: #{k}, pik: #{pik}"
				node_pik = @current_shape.p[layer_name].get_node_i(pik) #The kth largest set of labelled points in the current shape (ascending order)
				#Step 1.3
				label_pik = node_pik.key
				alpha_labels = rule.alpha.p[layer_name]
				label_alpha = alpha_labels.get_node(label_pik)
				if label_alpha
					#Step 1.4
					i = 0
					while (i < label_alpha.list.size) && ((dptr+1) < f)
						p_i = label_alpha.list.get_node_i(i).key
						distinct = true
						j = 0
						while distinct && (j < dp_alpha.size) #Check if p_i is distinct from the existing distinguishable points
							if (p_i == dp_alpha[j])
								distinct = false
							end
							j+=1
						end
						if distinct
							dptr += 1
							dp_alpha[dptr] = p_i.clone
							#map contains the index of the set of labelled points in the current shape which has the same label as p_i
							map[dptr] = pik
							if ((dptr+1) == f)
								segment1 = Segment.new(OrderedPoint.new(dp_alpha[0]), OrderedPoint.new(dp_alpha[1]))
								segment2 = Segment.new(OrderedPoint.new(dp_alpha[1]), OrderedPoint.new(dp_alpha[2]))
								if (segment1.line_descriptor.sine == segment2.line_descriptor.sine) #That is, the lines are collinear (they are always in the first and fourth quadrant)
									dptr = 1
									dp_alpha.delete_at(2)
								end
							end
						end
						i+=1
					end
					if ((dptr+1) < f)
						step_1_2_dist_points(rule, dp_alpha, map, f, dptr, k, layer_name)
					end
				else
					step_1_2_dist_points(rule, dp_alpha, map, f, dptr, k, layer_name)
				end
			end
		#end
	end
	
	
	#Auxiliar method for computing the determinant of a matrix
	def cramer(m, b)
		result = Array.new
		det = determinant(m)
		
		for i in 0..2
			c = substitute(m,b,i)
			
			temp_det = determinant(c)
			
			result[i] = temp_det/det
		end
		
		return result
	end
	
	#Auxiliar method for computing the determinant of a matrix
	def substitute(m,b,pos)
		result = Array.new
		result[0] = Array.new
		result[1] = Array.new
		result[2] = Array.new
		
		for i in 0..2
			for j in 0..2
				if j == pos
					result[i][j] = b[i]
				else
					result[i][j] = m[i][j]
				end
			end
		end
		
		return result
	end
	
	#m:: a matrix
	#
	#returns:: the determinant of matrix m
	def determinant(m)
		#Sarrus rule
		det = (m[0][0]*m[1][1]*m[2][2]) + (m[0][1]*m[1][2]*m[2][0]) + (m[0][2]*m[1][0]*m[2][1])- ((m[0][2]*m[1][1]*m[2][0]) + (m[0][1]*m[1][0]*m[2][2]) + (m[0][0]*m[1][2]*m[2][1]))
		
		return det
	end
	
	#a:: an Array of three positions
	#
	#returns:: the sum of elements in the array
	def sum(a)
		result = 0
		for i in 0..2
			result = result + a[i]
		end
		return result
	end
	
	#dp_alpha:: Array with three points of the left shape of a Rule. This three points have to form a triangle.
	#dp_current::Array with three points of the current shape. This three points have to form an equivalent triangle to that of dp_alpha
	#
	#returns:: the transformation that has to be applied in order to convert the triangle formed by dp_alpha into the one formed by dp_current.
	#The transformation is an Array of six positions [a, b, c, d, e, f]; c and f are the traslation coefficients and a, b, d, e are the scale and rotation factors.
	def get_transformation(dp_alpha, dp_current)
		#Construct the x-matrix
		m_x = Array.new
		b_x = Array.new
		
		m_x[0] = Array.new
		m_x[0][0] = dp_alpha[0].x
		m_x[0][1] = dp_alpha[0].y
		m_x[0][2] = 1
		b_x[0] = dp_current[0].x
		
		m_x[1] = Array.new
		m_x[1][0] = dp_alpha[1].x
		m_x[1][1] = dp_alpha[1].y
		m_x[1][2] = 1
		b_x[1] = dp_current[1].x
		
		m_x[2] = Array.new
		m_x[2][0] = dp_alpha[2].x
		m_x[2][1] = dp_alpha[2].y
		m_x[2][2] = 1
		b_x[2] = dp_current[2].x
		
		coef_x = cramer(m_x, b_x)
		
		#Construct the y-matrix
		m_y = Array.new
		b_y = Array.new
		
		m_y[0] = Array.new
		m_y[0][0] = dp_alpha[0].x
		m_y[0][1] = dp_alpha[0].y
		m_y[0][2] = 1
		b_y[0] = dp_current[0].y
		
		m_y[1] = Array.new
		m_y[1][0] = dp_alpha[1].x
		m_y[1][1] = dp_alpha[1].y
		m_y[1][2] = 1
		b_y[1] = dp_current[1].y
		
		m_y[2] = Array.new
		m_y[2][0] = dp_alpha[2].x
		m_y[2][1] = dp_alpha[2].y
		m_y[2][2] = 1
		b_y[2] = dp_current[2].y
		
		coef_y = cramer(m_y, b_y)
		
		result = Array.new
		for i in 0..2
			result[i] = coef_x[i]
		end
		for i in 3..5
			result[i] = coef_y[i-3]
		end
		return result
	end
	
	
def execute_with_general_policy(n_rules, linear_coefs, problem_module)
  reset
  final_state = false
  continue = true
  while (@execution_history.size < n_rules) && !final_state && continue #while the number of steps is less than the specified...
    state = State.new(@current_shape)
    final_state = problem_module.is_final_state?(state)
    
    if !final_state
    
      #Array of triples [rule, transformation, features]
      alternatives = problem_module.get_actions(state)
      
      applied = false
      while !applied && continue
        #Obtain the action for which the value is maximum
        selected_pos = nil
        max_value = nil
        max_features = nil
        state_action = nil
        alternatives_aux = alternatives.clone
        while !alternatives_aux.empty?
          i = rand(alternatives_aux.size)
          a = alternatives_aux[i]
          alternatives_aux.delete_at(i)
          s_a = StateAction.new(state, Action.new(a[0], a[1]))
          features = a[2]
          
          value = get_value(linear_coefs, features)
          
          if max_value
            if value > max_value
              max_value = value
              state_action = s_a
              max_features = features
              selected_pos = i
            end
          else
            selected_pos = i
            max_value = value
            state_action = s_a
            max_features = features
          end
        end
        
        if state_action
          applied = Shade.project.execution.apply_rule(state_action.action.rule_id, state_action.action.transformation)
        end
      
        if !applied && !alternatives.empty?
          alternatives.delete_at(selected_pos)
        elsif !applied
          continue = false
        end
      end

    end
  end
end
	
	
	#rule_id:: internal id of the rule to apply to the current shape
	#transformation:: optional argument; when it is specified, the possible transformations of the rule corresponding to rule_id are not computed
	#
	#Applies the specified rule to the current shape.
	def apply_rule(rule_id, transformation = nil, print = false)
		applied = nil
		rule = @grammar.search_rule_by_id(rule_id)
		
		#By deffinition, all our alpha shapes have at least three distinct labelled points that form a triangle, since in the initialization of
		#shapes, an Error is raised when this condition does not hold.
		
		#If there are labels in alpha that do not exist in the current shape, then the rule cannot be applied
		possible = true
		@current_shape.p.each_key { |layer_name|
			
			current_labels = @current_shape.p[layer_name]
			alpha_labels = rule.alpha.p[layer_name]
			if alpha_labels
				alpha_labels.reset_iterator
				
				while (possible && (alpha_label_node = alpha_labels.get_next))
					current_label_node = current_labels.get_node(alpha_label_node.key)
					if !current_label_node 
						#If an alpha label value do not exist in the current shape, then the rule cannot be applied
						possible = false
					elsif current_label_node.list.size < alpha_label_node.list.size
						#If for a given value of an alpha label, there are less points in the current shape than in the alpha shape,
						#then the rule cannot be applied
						possible = false
					end
				end
			end
			
		}	
		
		#If the rule can by this moment be applied
		if possible
			if transformation
				#flag_s= @current_shape.shape_expression(rule.alpha.transform(transformation),Constants::SUBSHAPE, Constants::SEGMENTS)
				#flag_p = @current_shape.shape_expression(rule.alpha.transform(transformation),Constants::SUBSHAPE, Constants::POINTS)
#				if (flag_s && flag_p) #The transformed alpha is a subshape of the current shape
			    #Apply the rule
					@execution_history.push [rule_id, transformation, @current_shape.clone]
					t_alpha_minus_beta = rule.alpha_minus_beta.transform(transformation)
					t_beta_minus_alpha = rule.beta_minus_alpha.transform(transformation)
					
					@current_shape.shape_expression(t_alpha_minus_beta, Constants::DIFFERENCE, Constants::SEGMENTS)
					@current_shape.shape_expression(t_alpha_minus_beta, Constants::DIFFERENCE, Constants::POINTS)
					
					@current_shape.shape_expression(t_beta_minus_alpha, Constants::UNION, Constants::SEGMENTS)
					@current_shape.shape_expression(t_beta_minus_alpha, Constants::UNION, Constants::POINTS)
					
					applied = true
					
					
					

					#We see if the Constraints are complied
					i = 0
					size = @constraints.size
					#puts"#{size}"
          #puts"#{@constraints}"
					complied = true
					while i < size && complied
						complied = @constraints[i].satisfied?()
						i += 1
					end
					
					if !complied

						undo
						applied = false

					end	
#				else
#					#puts "Not a subshape. Transformation: #{transformation}. Flag s: #{flag_s}. Flag p: #{flag_p}"
#					puts "Not a subshape"
#				end
				
				
			else
				#Choose first layer with at least three points in the left shape (we need it in order to compute the transformation)
				found = false
				i = 0
				layer_name = "Layer0"
				#TODO: put a while
				rule.alpha.p.each_key {|l_n|
					
					if !found
						if (rule.alpha.p[l_n])
							n_points = 0
							rule.alpha.p[l_n].reset_iterator
							while (n = rule.alpha.p[l_n].get_next)
								n_points += n.list.size
							end
							found = (n_points > 2)
							if found
								layer_name = l_n
								#puts layer_name
							end
						end
					end
					
					i += 1
				}
				#We suppose that there is always one non-empty layer
				possible_ts = possible_transformations(rule, layer_name, nil, true)
				#possible_ts = first_possible_transformation(rule)
				
				if !possible_ts.empty? #Then the rule can be applied to the current shape
					#puts "#{possible_ts.length} possible transformations of rule #{rule_id}"
					#Randomly choose the transformation to apply
					i = rand(possible_ts.size)
					chosen_transformation = possible_ts[i]
					
					#Apply the rule
					@execution_history.push [rule_id, chosen_transformation, @current_shape.clone]
					t_alpha_minus_beta = rule.alpha_minus_beta.transform(chosen_transformation)
					t_beta_minus_alpha = rule.beta_minus_alpha.transform(chosen_transformation)

					@current_shape.shape_expression(t_alpha_minus_beta, Constants::DIFFERENCE, Constants::SEGMENTS)
					@current_shape.shape_expression(t_alpha_minus_beta, Constants::DIFFERENCE, Constants::POINTS)
					
					@current_shape.shape_expression(t_beta_minus_alpha, Constants::UNION, Constants::SEGMENTS)
					@current_shape.shape_expression(t_beta_minus_alpha, Constants::UNION, Constants::POINTS)
										
					applied = true
					
					#We see if the Constraints are complied
					j = 0
					size = @constraints.size
					  #puts"#{size}"
            #puts"#{@constraints}"
					complied = true
					while j < size && complied
						complied = @constraints[j].satisfied?()
						j += 1
					end
					
					if !complied
						possible_ts.delete_at i
						undo
						applied = false
					end	
					
					while (!possible_ts.empty? && !complied)
						
						i = rand(possible_ts.size)
						chosen_transformation = possible_ts[i]
						#Apply the rule
						@execution_history.push [rule_id, chosen_transformation, @current_shape.clone]
						t_alpha_minus_beta = rule.alpha_minus_beta.transform(chosen_transformation)
						t_beta_minus_alpha = rule.beta_minus_alpha.transform(chosen_transformation)
						
						@current_shape.shape_expression(t_alpha_minus_beta, Constants::DIFFERENCE, Constants::SEGMENTS)
						@current_shape.shape_expression(t_alpha_minus_beta, Constants::DIFFERENCE, Constants::POINTS)
						
						@current_shape.shape_expression(t_beta_minus_alpha, Constants::UNION, Constants::SEGMENTS)
						@current_shape.shape_expression(t_beta_minus_alpha, Constants::UNION, Constants::POINTS)
						
						applied = true
						
						#We see if the Constraints are complied
						j = 0
						size = @constraints.size
						#puts"#{size}"
						#puts"#{@constraints}"
						complied = true
						while j < size && complied
							complied = @constraints[j].satisfied?()
							j += 1
						end
						
						if !complied
							possible_ts.delete_at i
							undo
							applied = false
						end	

					end
				end
			end
			
			if applied 
				@current_shape.create_pi
				if Shade.using_sketchup
					@current_shape.refresh(@show_labels)
					if @show_backtracking_steps
						Sketchup.active_model.active_view.refresh
						sleep(Constants::DELAY_TIME)
					end
				end
			end
			
		end
		
		return applied
	end
	
	
	#rule:: a Rule object
	#layer_name:: the name of the affected layer
	#shape:: optional argument; when it is specified, the possible transformations are computed over it instead of the current shape
	#
	#returns:: an array with all the possible transformations that can be applied to the left part of the specified rule in order to become
	#a subshape of the specified shape, or the current shape when there is no specified shape
	def possible_transformations(rule, layer_name, shape = nil, print = false)
		if !shape
			shape = @current_shape
		end
		#Step 1: Compute the fixed distinguishable points associated with rule.alpha (dp_alpha). They must form a triangle
		dp_alpha = Array.new #Fixed distinguishable points
		map = Array.new 
		possible_transformations = Array.new
		f = 3 #Shapes of type 1, because we force the existence of at least three distinguishable points forming a triangle
		#Step 1.1
		dptr = k = -1
		#Step 1.2
		step_1_2_dist_points(rule, dp_alpha, map, f, dptr, k, layer_name)
		if (dp_alpha.size == 3)
			#Pre-compute the l's of the formed triangle (l is the square of the distance between two points)
			l_alpha = Array.new
			#For the points 0 and 1
			l_alpha[0] = (((dp_alpha[0].y - dp_alpha[1].y)**2) + ((dp_alpha[0].x - dp_alpha[1].x)**2))
			#For the points 1 and 2
			l_alpha[1] = (((dp_alpha[1].y - dp_alpha[2].y)**2) + ((dp_alpha[1].x - dp_alpha[2].x)**2))
			#For the points 2 and 0
			l_alpha[2] = (((dp_alpha[2].y - dp_alpha[0].y)**2) + ((dp_alpha[2].x - dp_alpha[0].x)**2))
			#puts "dp_alpha[0]: #{dp_alpha[0].x}, #{dp_alpha[0].y}"
			#puts "dp_alpha[1]: #{dp_alpha[1].x}, #{dp_alpha[1].y}"
			#puts "dp_alpha[2]: #{dp_alpha[2].x}, #{dp_alpha[2].y}"
			
			#Step 2: [Backtracking process] Generate all possible mappings from dp_alpha to the current shape
			#Step 2.1
			index = Array.new
			dp_current = Array.new
			dptr = 0
			
			current_point_node = shape.p[layer_name].get_node_i(map[dptr]).list.first
			while (dptr >= 0)
				while current_point_node
					do_next = true
					if !current_point_node.list #The point has not been selected previously
						point_bis = current_point_node.key
						i = 0
						found = false
						while (i < dptr) && !found
							if (point_bis == dp_current[i])
								found = true
							end
							i+=1
						end
						if !found #point_bis is distinct from the already selected points
							dp_current[dptr] = point_bis
							if dptr < 2
								index[dptr] = current_point_node
								current_point_node.list = 1
								dptr += 1
								do_next = false
								current_point_node = shape.p[layer_name].get_node_i(map[dptr]).list.first
							else #we now have three points to do a mapping
								#We have to check if they form a triangle

								#puts "dp_current[0]: #{dp_current[0].x}, #{dp_current[0].y}"
								#puts "dp_current[1]: #{dp_current[1].x}, #{dp_current[1].y}"
								#puts "dp_current[2]: #{dp_current[2].x}, #{dp_current[2].y}"
								segment1 = Segment.new(OrderedPoint.new(dp_current[0]), OrderedPoint.new(dp_current[1]))
								segment2 = Segment.new(OrderedPoint.new(dp_current[1]), OrderedPoint.new(dp_current[2]))
								if (segment1.line_descriptor.sine != segment2.line_descriptor.sine) 
									#The lines are not collinear (they are always in the first and fourth quadrant and thus we can use the sine)
									#Now we have to check if the triangles are similar
									l_current = Array.new
									#For the points 0 and 1
									l_current[0] = (((dp_current[0].y - dp_current[1].y)**2) + ((dp_current[0].x - dp_current[1].x)**2))
									#For the points 1 and 2
									l_current[1] = (((dp_current[1].y - dp_current[2].y)**2) + ((dp_current[1].x - dp_current[2].x)**2))
									#For the points 2 and 0
									l_current[2] = (((dp_current[2].y - dp_current[0].y)**2) + ((dp_current[2].x - dp_current[0].x)**2))
									c = Array.new
									#For the points 0 and 1
									c[0] = (l_current[0]/l_alpha[0])
									#For the points 1 and 2
									c[1] = (l_current[1]/l_alpha[1])
									#For the points 2 and 0
									c[2] = (l_current[2]/l_alpha[2])	
									#puts "c's: #{c[0]}, #{c[1]}, #{c[2]}"
									if (eql_c_eps(c[0], c[1], c[2]))
										t = get_transformation(dp_alpha, dp_current)
										#puts t
										flag_s = false
										flag_p = shape.shape_expression(rule.alpha.transform(t), Constants::SUBSHAPE, Constants::POINTS, print)
										if flag_p
                      flag_s = shape.shape_expression(rule.alpha.transform(t), Constants::SUBSHAPE, Constants::SEGMENTS, print)
										end
										  
										
										#if print
											#puts "flag_s: #{flag_s}"
											#puts "flag_p: #{flag_p}"
											#puts "-----------------"
										#end
										
										if (flag_s && flag_p) #The transformed alpha is a subshape of the current shape
											possible_transformations.push t
										end
									end
								end
							end
						end
					end
					if do_next
						current_point_node = current_point_node._next
					end
				end
				#Backtrack
				dptr = dptr - 1
				if dptr >= 0
					current_point_node = index[dptr] #The previous selection
					current_point_node.list = nil
					current_point_node = current_point_node._next
				end
			end
		end
		return possible_transformations
	end
	
	
	#c1:: a float number
	#c2:: a float number
	#c3:: a float number
	#
	#returns:: true if the three numbers are equal with a tolerance given by Constants::EPSILON
	def eql_c_eps(c1, c2, c3)
		dif1 = (c1 - c2).abs
		result = (dif1 < Constants::EPSILON)
		dif2 = (c2 - c3).abs
		result = (result && (dif2 < Constants::EPSILON))
	end
	
	
	
	#Applies a random rule to the current shape
	def apply_rule_random()
		rules_index = Array.new
		for i in 0..(@grammar.rules.size-1)
			rules_index[i] = i
		end
		
		applied = false
		
		while (!applied && !rules_index.empty?)
			random_rule_index = rules_index[rand(rules_index.size)]
			random_rule_id = @grammar.rules[random_rule_index].rule_id
			applied = self.apply_rule(random_rule_id)
			
			if !applied
				rules_index.delete random_rule_index
			end
		end
		return applied
		
	end
	
	
	#shape:: optional argument; when it is specified, the possible brothers are computed over it instead of the current shape
	#
	#returns:: an array of pairs [rule_id, transformation] that can be applied to shape when specified, and to the current shape otherwise
	def brothers(shape = nil)
		brothers = Array.new
		show = false
		
		if @show_backtracking_steps
			show = true
			@show_backtracking_steps = false
		end
		
		@grammar.rules.each {|r|
			#Choose first non-empty layer
			found = false
			i = 0
			n_layers = r.alpha.p.keys.length
			layer_name = "Layer0"
			keys = r.alpha.p.keys
			while ((i < keys.size)&&(!found))
				l_n = keys[i]
				
				if !found
					if (r.alpha.p[l_n])
						n_points = 0
						r.alpha.p[l_n].reset_iterator
						while (n = r.alpha.p[l_n].get_next)
							n_points += n.list.size
						end
						found = (n_points > 2)
					end
					if found
						layer_name = l_n
					end
				end
				
				i += 1
			end
			
			possible_ts = possible_transformations(r, layer_name, shape)
			possible_ts.each {|t|
				brothers.push [r.rule_id, t]
			}
		}
		
		if show
			@show_backtracking_steps = true
		end
		
		return brothers
	end
	
	
	#n_rules:: number of random rules to apply
	#show_backtracking_steps:: true iff we want to see the steps
	#
	#return:: true if the desired number of rules has been applied
	def apply_n_rules_random(n_rules, show_backtracking_steps)
		reset #We need to start from the begining
		
		@backtracking_steps = 0
		@show_backtracking_steps = show_backtracking_steps
		
		t1 = Time.now
		success = backtracking(0, n_rules, show_backtracking_steps)
		t2 = Time.now
		
		#puts "Elapsed time: #{t2 - t1}"
		
		@show_backtracking_steps = false
		
		return success
	end
	
	#n_applied:: number of applied rules before calling this method
	#n_total:: number of rules to applu
	#show_backtracking_steps:: true iff we want to see the backtracking steps
	#
	#Applies rules in a backtracking process, until the solution is reached or the solution space is empty,
	#thus there is no possible solution.
	#returns true if the solution has been reached
	def backtracking(n_applied, n_total, show_backtracking_steps)
		if n_total > 0 #If we have some rules to apply...
			
			# Generate brothers (possible next steps) of this level
			brothers = brothers()
			
			# Do backtracking with the generated brothers
			solution = false
			while brothers.length > 0 && !solution #While more brothers are available and the solution is not reached...
				
				#We randomly choose the brother to apply
				brother = brothers[rand(brothers.size)]
				
				#brother[0] is the rule id; brother[1] is the transformation
				#Now we have the information to apply the rule
				applied = apply_rule(brother[0], brother[1])
				
				@backtracking_steps += 1
				
				if !applied #The step is not feasible
					#Delete our current brother
					brothers.delete brother
				else #The step is feasible
					if n_applied == n_total - 1 #If we have applied the number of desired rules...
						#Then we have the solution!
						solution = true
					else #If we have not reached the number of rules to apply...
						#We need to apply the remaining number of rules
						solution = backtracking(n_applied + 1, n_total, show_backtracking_steps)

						if !solution #If we do not reach the solution with this brother...
							@show_backtracking_steps = false
							#Undo the last step (the one of the last brother applied)
							undo
							@show_backtracking_steps = show_backtracking_steps
							#Delete our current brother
							brothers.delete brother
						end
					end
				end
			end	
		else #If the number of rules to apply is zero, we can always satisfy the request ;-)
			solution = true
		end
		
		#Finally, return the solution
		return solution
	end
	
	#show_backtracking_steps:: true iff we want to see the steps
	#timeout:: timeout for the backtracking algorithm. If it is zero, no timeout will be taken into account
	#
	#return:: true if the goals have been achieved
	def apply_goal_rules_random(show_backtracking_steps, timeout, n_max_rules)
		
		#Enable garbage collector
		GC.enable
		if !@goals.empty?
			t1 = Time.now
			reset #We need to start from the begining
			
			@backtracking_steps = 0
			@show_backtracking_steps = show_backtracking_steps
			
			if timeout != 0
			  @timeout = timeout
			  @timeout_reached = false
			  @beginning_time = Time.now
			  success = backtracking_goals(show_backtracking_steps, n_max_rules)
			  if @timeout_reached
				 UI.messagebox("Timeout reached")
			  end
			  @timeout = nil
			else
			  @timeout = nil
			  success = backtracking_goals(show_backtracking_steps, n_max_rules)
			end
			
			@show_backtracking_steps = false
			t2 = Time.now
			#puts "Elapsed time: #{t2 - t1}"
		else
			success = -1
		end
		return success
	end
	
	#show_backtracking_steps:: true iff we want to see the backtracking steps
	#
	#Applies rules in a backtracking process, until the goals are satisfied or the solution space is empty,
	#thus there is no possible solution.
	#returns true if the solution has been reached
	def backtracking_goals(show_backtracking_steps, n_max_rules)
		
		if !self.goals_satisfied?() #If we have not reached the solution...
			
			GC.start
			# Generate brothers (possible next steps) of this level
			#puts "Calculando brothers"
			a_brothers = brothers()
			
			# Do backtracking with the generated brothers
			solution = false
			while ((a_brothers.length > 0) && (!solution)) #While more brothers are available and the solution is not reached...
				
				
				#We randomly choose the brother to apply
				brother = a_brothers[rand(a_brothers.size)]
				
				#brother[0] is the rule id; brother[1] is the shape index
				#Now we have the information to apply the rule
				#puts "Aplicando regla #{brother[0]}"
				applied = apply_rule(brother[0], brother[1])
				
				@backtracking_steps += 1
				
				if !applied #The step is not feasible (i.e., the Constraints are not complied)
					#Delete our current brother
					
					a_brothers.delete brother
					#puts "Borrando brother, regla no aplicada. Quedan #{a_brothers.size} brothers"
				else #The step is feasible (i.e., the Constraints are complied)
					if self.goals_satisfied?() #If the design satisfies the present goals
						#Then we have the solution!
						#puts "Soluci�n alcanzada"
						solution = true
					else #If we have not reached the solution...
						#puts "backtracking goals #{Time.now}"
						# IF we have reached the maximum number of applications
						if (n_max_rules && (@execution_history.size == n_max_rules))
							#puts "N�mero m�ximo de reglas alcanzado"
							#We do not follow this path; it is too large
							@show_backtracking_steps = false
							#Undo the last step (the one of the last brother applied)
							undo
							@show_backtracking_steps = show_backtracking_steps
							#Delete our current brother
							a_brothers.delete brother
						else
							#We need to apply the remaining number of rules
							#puts "Backtracking"
							solution = backtracking_goals(show_backtracking_steps, n_max_rules)

							#puts "Borrando brother, soluci�n no alcanzada por este camino"
							if !solution #If we do not reach the solution with this brother...
								@show_backtracking_steps = false
								#Undo the last step (the one of the last brother applied)
								undo
								@show_backtracking_steps = show_backtracking_steps
								#Delete our current brother
								a_brothers.delete brother
							end
						end
					end
				end
			end	
		else #If we have reached the solution...
			solution = true
		end
		
		#Finally, return the solution
		return solution
	end
	
	#returns:: true iff every present goal is satisfied. If no goals are present, it returns true
	def goals_satisfied?
		satisfied = true
		size = @goals.length
		i = 0
		while i < size && satisfied
			satisfied = @goals[i].satisfied?
			i+=1
		end
		return satisfied
	end
	
	#Undoes the last taken step (that is, the current shape becomes the one that existed when the last rule had not been applied)
	def undo
		
		pair = @execution_history.pop
		if pair
			@current_shape.erase
			@current_shape = pair[2]
			@current_shape.refresh
		end
	end
	
	#Resets the execution, so the current shape becomes the axiom again
	def reset
		@execution_history = Array.new
		if @current_shape
			@current_shape.erase
		end
		
		@current_shape = CurrentLabelledShape.new(Array.new, Array.new)
		
		@grammar.axiom.p.each_key {|layer_name|
			@current_shape.p[layer_name] = @grammar.axiom.p[layer_name].clone
		}
		
		@grammar.axiom.s.each_key {|layer_name|
			@current_shape.s[layer_name] = BalancedBinaryTree.new
			@grammar.axiom.s[layer_name].reset_iterator
			while (s_node = @grammar.axiom.s[layer_name].get_next)
				@current_shape.s[layer_name].insert_node BalancedBinaryTreeNode.new(0, nil, nil, s_node.key, s_node.list.clone)
			end
		}
		
		@current_shape.create_pi
		@current_shape.paint(@show_labels)
	end
	
	
	#Executes the grammar until no more rules can be applied. Be careful: it can turns into an endless loop
	def execute_until_end
		#puts "Applying rules..."
		applied = true
		while applied
			applied = apply_rule_random()
		end
		#puts "End reached"
	end
end
#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#This class gathers an Execution object and the necessary information in order to save it in a file
class Project
	
	#The Execution object
	attr_accessor :execution
	#The title
	attr_reader :title
	#True iff the project is saved
	attr_writer :saved
	#Path in which the project has been saved
	attr_reader :path
	#true iff the view is been refreshed
	attr_accessor :modifying
	#true iff a rule shape is being deleted
	attr_accessor :erasing
	
	#Initializing
	def initialize(execution)
		@execution = execution
		
		@saved = true
		@path = nil       #the path in the OS file system
		
		@title = Constants::DEFAULT_PROJECT_TITLE
		
		@modifying = false
		
		@erasing = false

	end
	
	#path:: path to save the project in
	#
	#Saves the project in the specified path
	def save(path = @path, text = false)
		#the path is a .prj file
		#we need the directory
		directory = ShadeUtils.get_directory_from_path(path)
		title = ShadeUtils.get_title_from_path(path)
		File.open(path.strip, 'w') do |f|
			f.write("#{title}Grammar.gr2\n")
			@execution.constraints.each { |c|
				f.write "C:"
				f.write c.name + "\n"
			}
			@execution.goals.each { |g|
				f.write "G:"
				f.write g.name + "\n"
			}
		end
		@path = path
		@execution.grammar.save("#{directory}#{title}Grammar.gr2", text)
		@saved = true
	end
	
	#Returns true if both the project and its related grammar are saved
	def saved()
		return (@execution.grammar.saved and @saved)
	end
	
	#Removes all the attached observers
	def remove_observers()
		if Shade.using_sketchup
			size = execution.grammar.rules.size
			i = 0
			while i < size
				execution.grammar.remove_rule(size-i-1)
				i += 1
			end

			Sketchup.active_model.entities.remove_observer Shade.rule_groups_observer
			Shade.rule_groups_observer = nil
			GC.start
		end
	end
	
	#new_title:: String with the new title for the project
	#closing:: true iff SketchUp is being closed
	#
	#Changes the title of the project to new_title
	def set_title(new_title, closing = false)
		@title = title
		if Shade.using_sketchup
			if !closing
				if @title_text
					Sketchup.active_model.entities.erase_entities @title_text
				end
				if Shade.show_text
					@title_text = Sketchup.active_model.entities.add_text("Project: " + @title, Constants::PT_PROJECT_TEXT)
				end
			end
		end
	end
	
	#path:: new path
	#closing:: true iff we are closing SU
	#
	#Sets the path
	def set_path(path, closing = false)
		#Set the path attribute
		@path = path
		
		if path
			set_title(ShadeUtils.get_title_from_path(path), closing)
		else
			set_title(Constants::DEFAULT_PROJECT_TITLE, closing)
		end
	end
	
	#path:: path to load the project from
	#
	#Loads the project from the specified path
	def load(path)
		@path = path
		#the path is a .prj file
		#we need the directory
		directory = ShadeUtils.get_directory_from_path(path)
		
		@execution.constraints = Array.new
		@execution.goals = Array.new
		
		
		File.open(path.strip, 'r') do |f|
			while line = f.gets
				line_a = line.split(':')
				if (line_a[0] == "C") #Load a constraint
					constraint_name = line_a[1].strip
					i = 0
					found = false
					while (i < Shade.constraint_class_names.size) && !found
						if Shade.constraint_class_names[i][1] == constraint_name
							found = true
							constraint_class = Shade.constraint_class_names[i][0]
							@execution.add_constraint(constraint_class.new)
						end
						i += 1
					end
				elsif (line_a[0] == "G") #Load a goal
					goal_name = line_a[1].strip
					i = 0
					found = false
					while (i < Shade.goal_class_names.size) && !found
						if Shade.goal_class_names[i][1] == goal_name
							found = true
							goal_class = Shade.goal_class_names[i][0]
							@execution.add_goal(goal_class.new)
						end
						i += 1
					end
				else
					grammar_title = line.strip
					@execution.grammar.load("#{directory}#{grammar_title}")
				end
			end
		end
		

	end
	
	#force:: true if we want to force refreshing, even when no changes have been registered
	#
	#Refreshes the view of the shapes in the project (that is, the rule shapes and the current shape)
	def refresh(force = false)
		if Shade.using_sketchup
			@modifying = true
			if @execution
				@execution.current_shape.refresh(@execution.show_labels, @execution.hide_black)
				if @execution.grammar
					@execution.grammar.rules.each {|rule|
						rule.alpha.refresh(force)
						rule.beta.refresh(force)
					}
				end
			end
			@modifying = false
		end
	end
	
end

#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#This class wrapps some global variables, including the current project
class Shade
	
	def Shade.flats_generated
		return @@flats_generated
	end
	
	def Shade.flats_generated=(flats_generated)
		@@flats_generated = flats_generated
	end
	
	#returns:: true if SketchUp is being used 
	def Shade.using_sketchup
		return @@using_sketchup
	end
	
	#using_sketchup:: true if SketchUp is being used
	#
	#Sets the flag using_sketchup to the specified value
	def Shade.using_sketchup=(using_sketchup)
		@@using_sketchup = using_sketchup
	end

	#returns:: the current Project object
	def Shade.project
		return @@project
	end
	
	#project:: a Project object
	#
	#Sets the project
	def Shade.project=(project)
		@@project = project
	end
	
	#returns:: the RuleGroupsObserver object
	def Shade.rule_groups_observer
		return @@rule_groups_observer
	end
	
	#rule_groups_observer:: a RuleGroupsObserver object
	#
	#Sets the rule groups observer
	def Shade.rule_groups_observer=(rule_groups_observer)
		@@rule_groups_observer = rule_groups_observer
	end
	
	#returns:: the flag show_text
	def Shade.show_text
		return @@show_text
	end
	
	#show_text:: true iff text is to be shown in the SketchUp canvas (titles for the project and the grammar)
	#
	#Sets the show_text flag
	def Shade.show_text=(show_text)
		@@show_text = show_text
	end
	
	#label_radius:: the desired radius, in meters, for the labels
	#
	#Sets the label radius to the specified value
	def Shade.label_radius=(label_radius)
		@@label_radius = label_radius
	end
	
	#returns:: the current label radius
	def Shade.label_radius
		return @@label_radius
	end
	
	#constraint_class_name:: a String with the name for a new constraint class
	#
	#Adds the new name to the list of taken constraint class names
	def Shade.add_constraint_class_name(constraint_class_name)
		@@constraint_class_names.push constraint_class_name
	end
	
	#constraint_class_names:: an Array of Strings with all the taken constraint class names
	#
	#Sets the constraint class names list to the specified one
	def Shade.constraint_class_names=(constraint_class_names)
		@@constraint_class_names = constraint_class_names
	end
	
	#returns:: the current constraint class names list
	def Shade.constraint_class_names
		return @@constraint_class_names
	end
	
	#goal_class_name:: a String with the name for a new goal class
	#
	#Adds the new name to the list of taken goal class names
	def Shade.add_goal_class_name(goal_class_name)
		@@goal_class_names.push goal_class_name
	end
	
	#goal_class_names:: an Array of Strings with all the taken goal class names
	#
	#Sets the goal class names list to the specified one
	def Shade.goal_class_names=(goal_class_names)
		@@goal_class_names = goal_class_names
	end
	
	#returns:: the current goal class names list
	def Shade.goal_class_names
		return @@goal_class_names
	end
	
	#robot:: a Robot object for project scripting
	#
	#Sets the current robot to the specified one
	def Shade.robot=(robot)
		@@robot = robot
	end
	
	#returns:: the curren robot. If no robot has been loaded, it returns nil
	def Shade.robot
		return @@robot
	end
	
	
  def Shade.policy=(value)
    @@policy = value
  end
  
  def Shade.policy
    return @@policy 
  end
  
  def Shade.problem_module=(value)
    @@problem_module = value
  end
    
  def Shade.problem_module
    return @@problem_module 
  end
  
  def Shade.design_current_path=(value)
    @@design_current_path = value
  end
    
  def Shade.design_current_path
    return @@design_current_path
  end
  
  def Shade.grammar_loaded=(value)
      @@grammar_loaded = value
    end
      
  def Shade.grammar_loaded
     return @@grammar_loaded
  end
  
  def Shade.rule_ob=(value)
       @@rule_ob = value
     end
       
   def Shade.rule_ob
      return @@rule_ob
   end
   
  def Shade.modified=(value)
       @@modified = value
     end
       
   def Shade.modified
      return @@modified
   end
   
   def Shade.contour_face=(contour_face)
	   @@contour_face = contour_face
   end
   
   def Shade.contour_face
	   return @@contour_face
   end
   
   def Shade.montaner_status=(montaner_status)
	   @@montaner_status = montaner_status
   end
   
   def Shade.montaner_status
	   return @@montaner_status
   end
   
   def Shade.montaner_actions=(montaner_actions)
	   @@montaner_actions = montaner_actions
   end
   
   def Shade.montaner_actions
	   return @@montaner_actions
   end
   
   def Shade.montaner_shape=(montaner_shape)
	   @@montaner_shape = montaner_shape
   end
   
   def Shade.montaner_shape
	   return @@montaner_shape
   end
   
   def Shade.previous_montaner_shape=(previous_montaner_shape)
	   @@previous_montaner_shape = previous_montaner_shape
   end
   
   def Shade.previous_montaner_shape
	   return @@previous_montaner_shape
   end
   
   def Shade.montaner_history=(montaner_history)
	@@montaner_history = montaner_history
end

def Shade.montaner_history
	return @@montaner_history
end
  
	
end

	
#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#This class represents a robot, that is, a set of projects that are executed in some specified ordering, so as to automatically produce a set of designs
class Robot
	
	attr_accessor :project_paths
	attr_accessor :execution_modes
	
	#Initializing the robot
	def initialize
		@project_paths = Array.new
		@execution_modes = Array.new
	end
	
	#path:: the path to save the robot in
	#
	# Saves the robot in the specified path
	def save(path)
		#the path is a .txt file
		#we need the directory
		directory = ShadeUtils.get_directory_from_path(path)
		title = ShadeUtils.get_title_from_path(path)
		
		old_project_path = Shade.project.path
		
		File.open(path.strip, 'w') do |f|
			@project_paths.each_with_index { |project, i|
				project_title = ShadeUtils.get_title_from_path(project)
				f.write("#{project_title}:#{@execution_modes[i]}\n")

				Shade.project.load(project)
				Shade.project.save("#{directory}\\#{project_title}.prj", true)
			}
		end	
		
		if old_project_path
			Shade.project.load(old_project_path)
			
			Shade.project.execution.reset
			Shade.project.refresh(true)
		else
			ShadeUtils.create_default_project
		end
	end

	#path:: the path to save the robot from
	#
	# Loads the robot from the specified path
	def load(path)
		@project_paths = Array.new
		@execution_modes = Array.new
		File.open(path.strip, 'r') do |f|
			while line = f.gets
				line_a = line.split(':')

				project_path = "#{File.dirname(path)}\\#{line_a[0]}.prj"
				execution_mode = line_a[1].strip
				@project_paths.push project_path
				@execution_modes.push execution_mode	
			end
		end
	end
	
	#number_of_designs:: number of designs to be generated
	#design_directory:: directory to save the generated designs in
	#
	# Executes the robot 
	def execute(number_of_designs, design_directory)
		goals_command_directory = "#{File.dirname(__FILE__)}/commands/random-goal-execute-command.rb"
		goals_command_directory.gsub!("/", "\\")
		
		current_shape_directory = "#{File.dirname(__FILE__)}/commands/temp/current_shape.txt"
		current_shape_directory.gsub!("/", "\\")
		
		project_directory = "#{File.dirname(__FILE__)}/commands/temp/project.txt"
		project_directory.gsub!("/", "\\")
		
		n_command_directory = "#{File.dirname(__FILE__)}/commands/n-execute-random-command.rb"
		n_command_directory.gsub!("/", "\\")
		
		for i in 1..number_of_designs.to_i
			design_path = "#{design_directory}\\design#{i}.txt"
			
			first = true
			
			t1 = Time.now
			@project_paths.each_with_index { |project_path, p|
				
				Shade.project.load(project_path)
				Shade.project.execution.reset
				
				if !first
					new_axiom = LabelledShape.new(Array.new, Array.new)
					new_axiom.load(current_shape_directory)
					Shade.project.execution.file_axiom = true
					Shade.project.execution.grammar.axiom = new_axiom
					Shade.project.execution.reset
					
					Shade.project.execution.current_shape.refresh
					Shade.project.execution.current_shape.create_pi
				end
				
				mode = @execution_modes[p]
				
				#Save project into fix .txt file
				Shade.project.save(project_directory, true)
				
				#Save current shape into fix .txt file
				Shade.project.execution.current_shape.save(current_shape_directory)
				
				#Save execution history
				history_directory = "#{File.dirname(__FILE__)}/commands/temp"
				history_directory.gsub!("/", "\\")
				Shade.project.execution.save_execution_history(history_directory)
				
				if mode == "Goals"
					output = system("ruby \"#{goals_command_directory}\" 0 1000")
				else
					output = system("ruby \"#{n_command_directory}\" #{mode.to_i}")
				end
				
				#Catch return from external command				
				if !($? == 0)
					UI.messagebox("The loaded constraints/goals of #{project_path} use some functions of SketchUp API. The execution will be performed inside the SketchUp environment, and it may take more time.")
					
					if mode == "Goals"
						success = Shade.project.execution.apply_goal_rules_random(false, 0, 1000)
					else
						success = Shade.project.execution.apply_n_rules_random(mode.to_i, false)
					end
					if !success
						UI.messagebox("Failure. Impossible to satisfy goals in #{project_path}.")
					else
						#Save current shape into fix .txt file
						Shade.project.execution.current_shape.save(current_shape_directory)
					end
				else
					log_directory = "#{File.dirname(__FILE__)}/commands/temp/result.log"
					log_directory.gsub!("/", "\\")
					File.open(log_directory, 'r') do |f|
						line = f.gets.strip
						if (line == "false")
							UI.messagebox("Failure. Impossible to satisfy goals in #{project_path}.")
						end
							
					end	
				end

				first = false
			}
			Shade.project.execution.current_shape.load(current_shape_directory)
			Shade.project.execution.current_shape.refresh
			Shade.project.execution.current_shape.create_pi
			Shade.project.execution.current_shape.save(design_path)
			t2 = Time.now
			puts "Elapsed time for design #{i}: #{t2 - t1} seconds"
			#delete files of temporal directory
			dir = Dir.new("#{File.dirname(__FILE__)}/commands/temp")
			dir.each { |file_name|
				if file_name == '.' or file_name == '..' then next
				else File.delete("#{File.dirname(__FILE__)}/commands/temp/#{file_name}")
				end
			}
			
		end
		
	end
end