
class SpecFile 
  attr_accessor :file_path
  attr_accessor :spec_contexts
  attr_reader :lines
  attr_reader :file_name
	

	attr_accessor :local_work_path
	
  def initialize(file_path, content_lines = nil)
    @spec_contexts = []
    @lines = []
    if content_lines then
      @lines = content_lines
    elsif file_path then
      @file_path= file_path
      @file_name = File.basename(@file_path)
      File.open(@file_path) do |file|
        file.each_line  { |line| @lines << line.rstrip }
      end
    end
    parse(@lines)
  end

  def test_case_count
    count = 0
    @spec_contexts.each do |context|
      count += context.spec_behaviours.size
    end
    return count
  end

  def parse(lines)
    cache_behaviours = []
    cache_contexts = []

    new_context = nil
    lines.each_with_index { |line, idx|

      if new_context && line =~ /^\s*before\(:each\)\s+do\s*$/
        new_context.before_each_line_start = idx + 1
      elsif new_context && line =~ /^\s*before\(:all\)\s+do\s*$/
        new_context.before_all_line_start= idx + 1
      elsif new_context && line =~ /^\s*after\(:each\)\s+do\s*$/
        new_context.after_each_line_start= idx + 1
      elsif new_context && line =~ /^\s*after\(:all\)\s+do\s*$/
        new_context.after_all_line_start= idx + 1
      end

      if line =~ /^\s*(context|describe|spec|specification|test_suite|suite)\s+(.*)\s+do/
        new_context = SpecContext.new($2, self)
        new_context.start_line = idx + 1
        cache_contexts << new_context
      elsif new_context && line =~ /^\s*(specify|it|story|scenario|test_case|use_case|test)\s+(.*)\s+do/
        new_behaviour = SpecBehaviour.new($2, self)
        new_behaviour.start_line = idx + 1
        new_context.first_test_case_line_start =  new_behaviour.start_line unless new_context.first_test_case_line_start
        cache_behaviours << new_behaviour
      end
    }

    cache_behaviours.reverse.each { |behaviour|
      cache_contexts.reverse.each { |context|
        if behaviour.start_line > context.start_line
          context.spec_behaviours <<  behaviour
          behaviour.spec_context = context
          break
        end
      }
    }

    cache_contexts.each { |ctx| ctx.spec_behaviours.reverse!; @spec_contexts << ctx }

    last_ctx = nil
    @spec_contexts.reverse.each_with_index { |ctx, idx|

      if idx == 0
        ctx.end_line = lines.size # will using -1 for range
        last_ctx = ctx
        next
      end

      ctx.end_line = last_ctx.start_line - 1
      last_ctx = ctx
    }

    last_beh = nil
    @spec_contexts.each_with_index { |ctx, idx|
      ctx.spec_behaviours.reverse.each_with_index { |beh, bdx|
        if bdx == 0 then
          beh.end_line = ctx.end_line - 1
          last_beh = beh
          next
        end

        beh.end_line = last_beh.start_line - 1
        last_beh = beh
      }
    }


    normalize
  end

  def to_s
    str = "File :#{file_path}\n"
    @spec_contexts.each { |ctx|
      str << "  context: #{ctx.name} - (#{ctx.start_line} : #{ctx.end_line})\n"
      ctx.spec_behaviours.each { |beh|
        str << "    behaviour: #{beh.name} - (#{beh.start_line} : #{beh.end_line})\n"
      }
    }
    str
  end


  def behaviour_lookups
    lookups = {}
    @spec_contexts.each { |ctx|
      ctx.spec_behaviours.each { |beh|
        lookups[beh.name.strip] = beh
      }
    }
    return lookups
  end

  def get_behaviour_by_line(line_number)
    @spec_contexts.each { |ctx|
      if (line_number >= ctx.start_line && line_number <= ctx.end_line) then
        ctx.spec_behaviours.each { |beh|
          return beh if line_number >= beh.start_line && line_number <= beh.end_line
        }

        return ctx
      end
    }

    return self
  end

  def name
    @file_name
  end
  alias display_name name

  def start_line
    1
  end

  def end_line
    lines.size
  end

  def is_web_test?
    spec_content =  @lines.join("")
    spec_content.include?("RWebUnit::") or spec_content.include?("open_browser")
  end



  def normalize
    @spec_contexts.each { |ctx|
      ctx.normalize
    }
  end


  def get_spec_context_by_line(line)
    @spec_contexts.each { |ctx|
      return ctx if line < ctx.end_line && line > ctx.start_line
    }
    return nil
  end
end