require 'rubyXL/objects/ooxml_object'
require 'rubyXL/objects/simple_types'
require 'rubyXL/objects/text'
require 'rubyXL/objects/formula'

module RubyXL

  # http://www.schemacentral.com/sc/ooxml/e-ssml_v-1.html
  class CellValue < OOXMLObject
    define_attribute(:_, :string, :accessor => :value)
    define_attribute(:'xml:space', :string)
    define_element_name 'v'

    def before_write_xml
      self.xml_space = (value.is_a?(String) && ((value =~ /\A\s/) || (value =~ /\s\Z/) || value.include?("\n"))) ? 'preserve' : nil
      true
    end
  end

  # http://www.schemacentral.com/sc/ooxml/e-ssml_c-2.html
  class Cell < OOXMLObject
    define_attribute(:r,   :ref)
    define_attribute(:s,   :int,  :default => 0, :accessor => :style_index)
    define_attribute(:t,   RubyXL::ST_CellType,  :accessor => :datatype, :default => 'n' )
    define_attribute(:cm,  :int,  :default => 0)
    define_attribute(:vm,  :int,  :default => 0)
    define_attribute(:ph,  :bool, :default => false)
    define_child_node(RubyXL::Formula,   :accessor => :formula)
    define_child_node(RubyXL::CellValue, :accessor => :value_container) 
    define_child_node(RubyXL::RichText)    # is
    define_element_name 'c'

    def index_in_collection
      r.col_range.begin
    end

    def row
      r && r.first_row
    end

    def row=(v)
      self.r = RubyXL::Reference.new(v, column || 0)
    end

    def column
      r && r.first_col
    end

    def column=(v)
      self.r = RubyXL::Reference.new(row || 0, v)
    end

    def raw_value
      value_container && value_container.value
    end

    def raw_value=(v)
      self.value_container ||= RubyXL::CellValue.new
      value_container.value = v
    end

    def number_format
      workbook.stylesheet.get_number_format_by_id(get_cell_xf.num_fmt_id)
    end

    def is_date?
      return false unless raw_value =~ /\A\d+(?:\.\d+)?\Z/ # Only fully numeric values can be dates
      num_fmt = self.number_format
      num_fmt && num_fmt.is_date_format?
    end

    # Gets massaged value of the cell, converting datatypes to those known to Ruby (that includes
    # stripping any special formatting from RichText).
    def value(args = {})
      return raw_value if args[:raw]
      case datatype
      when RubyXL::DataType::SHARED_STRING then
        workbook.shared_strings_container[raw_value.to_i].to_s
      else 
        if is_date? then workbook.num_to_date(raw_value.to_f)
        elsif raw_value.is_a?(String) && (raw_value =~ /\A-?\d+(\.\d+(?:e[+-]\d+)?)?\Z/i) # Numeric
          if $1 then raw_value.to_f
          else raw_value.to_i
          end
        else raw_value
        end
      end
    end

    include LegacyCell
  end

#TODO#<row r="1" spans="1:1" x14ac:dyDescent="0.25">

  # http://www.schemacentral.com/sc/ooxml/e-ssml_row-1.html
  class Row < OOXMLObject
    define_attribute(:r,            :int)
    define_attribute(:spans,        :string)
    define_attribute(:s,            :int,   :default => 0, :accessor => :style_index)
    define_attribute(:customFormat, :bool,  :default => false)
    define_attribute(:ht,           :double)
    define_attribute(:hidden,       :bool,  :default => false)
    define_attribute(:customHeight, :bool,  :default => false)
    define_attribute(:outlineLevel, :int,   :default => 0)
    define_attribute(:collapsed,    :bool,  :default => false)
    define_attribute(:thickTop,     :bool,  :default => false)
    define_attribute(:thickBot,     :bool,  :default => false)
    define_attribute(:ph,           :bool,  :default => false)
    define_child_node(RubyXL::Cell, :collection => true, :accessor => :cells)
    define_element_name 'row'

    attr_accessor :worksheet

    def index_in_collection
      r - 1
    end

    def [](ind)
      cells[ind]
    end

    def size
      cells.size
    end

    def insert_cell_shift_right(c, col_index)
      cells.insert(col_index, c)
      update_cell_coords(col_index)
    end

    def delete_cell_shift_left(col_index)
      cells.delete_at(col_index)
      update_cell_coords(col_index)
    end

    def update_cell_coords(start_from_index)
      cells.drop(start_from_index).each_with_index { |cell, i|
        next if cell.nil?
        cell.column = start_from_index + i
      }
    end
    private :update_cell_coords

    def xf
      @worksheet.workbook.cell_xfs[self.style_index || 0]
    end

    def get_fill_color
      @worksheet.workbook.get_fill_color(xf)
    end

    def get_font
      @worksheet.workbook.fonts[xf.font_id]
    end
  end

  # http://www.schemacentral.com/sc/ooxml/e-ssml_sheetData-1.html
  class SheetData < OOXMLObject
    define_child_node(RubyXL::Row, :collection => true, :accessor => :rows)
    define_element_name 'sheetData'

    def [](ind)
      rows[ind]
    end

    def size
      rows.size
    end

  end

end
