######################################################################
# Spreadsheet Alpha 2
#
# Changelog
# =========
# - Excel is now a subclass of File
# - Method write() was changed to write_data() to avoid IO confusion
# - Type checking in write_data() now done with kind_of? method instead
# - Uses big_endian? boolean instead of @byte_order value
######################################################################
module Spreadsheet

   class OutOfRangeException < RuntimeError; end
   class InvalidTypeException < RuntimeError; end

   class Excel < File

      RowMax = 65536
      ColMax = 256
      StrMax = 255
   
      def initialize(filename)
         super(filename,"w+")

         @dim_offset = 0
         @big_endian? = false

         # Big Endian or Little Endian architecture?
         if [1].pack("I") == [1].pack("N")
            @big_endian? = true
         end

         write_bof()
         write_dimensions()
      end

      def write_bof

         name    = 0x0809 # Record identifier
         len     = 0x0008 # Number of bytes
         version = 0x0000
         type    = 0x0010 # Worksheet
         build   = 0x0000 # Set to zero
         year    = 0x0000 # Set to zero

         header = [name,len].pack("vv")
         data   = [version,type,build,year].pack("vvvv")
         hd     = header + data

         print(hd)

      end

      def write_dimensions(row_min=0,row_max=0,col_min=0,col_max=0)

         row_max += 1
         col_max += 1
         
         name = 0x0000
         len  = 0x000A
         res  = 0x0000

         header = [name,len].pack("vv")
         data   = [row_min,row_max,col_min,col_max,res].pack("vvvvv")
         hd     = header + data

         @dim_offset = tell
         print(hd)

      end

      def write_eof
         
         name = 0x000A
         len  = 0x0000

         header = [name,len].pack("vv")
         print(header)
         seek(@dim_offset,0)
         write_dimensions()

      end

      def close
         write_eof()
         super
      end

      def write_data(row=0,col=0,data=nil)
         if data.kind_of?(String)
            write_string(row,col,data)
         elsif data.kind_of(Fixnum)
            write_number(row,col,data)
         else
            raise InvalidTypeException
         end 
      end

      def write_string(row,col,string)

         raise OutOfRangeException if row > RowMax
         raise OutOfRangeException if col > ColMax

         name = 0x0204 # Record identifier
         xf   = 0x0000 # Cell format

         strlen = string.length

         string.slice!(0,StrMax) if strlen > StrMax

         len  = 0x0008 + strlen # Bytes to follow

         header = [name,len].pack("vv")
         data   = [row,col,xf,strlen].pack("vvvv")
         hds = header + data + string

         print(hds)
      end

      def write_number(row,col,num)

         raise OutOfRangeException if row > RowMax
         raise OutOfRangeException if col > ColMax

         name = 0x0203
         len  = 0x000E
         xf   = 0x0000

         header = [name,len].pack("vv")
         data   = [row,col,xf].pack("vvv")
         xld    = [num].pack("d")

         xld = xld.to_s.reverse if @big_endian?

         hdx = header + data + xld

         print(hdx)

      end
   end
end