module Fox
  
  class FXIconItem
    def <=>(otherItem)
      text <=> otherItem.text
    end
  end

  class FXListItem
    def <=>(otherItem)
      text <=> otherItem.text
    end
  end
  
  class FXTreeItem
    def <=>(otherItem)
      text <=> otherItem.text
    end
  end
  
  #
  # Point
  #
  class FXPoint
  
    alias initializeXY initialize
   
    #
    # Returns an initialized FXPoint instance.
    #
    def initialize(*args)
      if args.length == 0
        initializeXY(0, 0)
      elsif args.length == 1
        if args[0].kind_of?(FXSize)
          initializeXY(args[0].w, args[0].h)
        elsif args[0].kind_of?(FXPoint)
          initializeXY(args[0].x, args[0].y)
        else
          raise TypeError, 'expected FXPoint or FXSize'
        end
      else
        initializeXY(args[0], args[1])
      end
    end
    
    def clone
      FXPoint.new(x, y)
    end 
    
    def ==(other)
      if other.kind_of?(FXPoint)
        (self.x == other.x) && (self.y == other.y)
      else
        false
      end
    end
    
    def -@
      FXPoint.new(-self.x, -self.y)
    end
    
    def +(other)
      if other.kind_of?(FXPoint)
        FXPoint.new(self.x + other.x, self.y + other.y)
      elsif other.kind_of?(FXSize)
        FXPoint.new(self.x + other.w, self.y + other.h)
      else
        raise TypeError, 'expected FXPoint or FXSize'
      end
    end
    
    def -(other)
      if other.kind_of?(FXPoint)
        FXPoint.new(self.x - other.x, self.y - other.y)
      elsif other.kind_of?(FXSize)
        FXPoint.new(self.x - other.w, self.y - other.h)
      else
        raise TypeError, 'expected FXPoint or FXSize'
      end
    end
    
    def *(other)
      FXPoint.new(other*self.x, other*self.y)
    end
    
    def /(other)
      FXPoint.new(self.x/other, self.y/other)
    end
  end
  
  #
  # Rectangle
  #
  class FXRectangle
  
    alias initialize4 initialize
   
    #
    # Returns an initialized FXRectangle instance.
    #
    def initialize(*args)
      if args.length == 0
        initialize4(0, 0, 0, 0)
      elsif args.length == 2
        if args[0].kind_of?(FXPoint) && args[1].kind_of?(FXSize)
          p = args[0]
          s = args[1]
          initialize4(p.x, p.y, s.w, s.h)
        else
          topleft = args[0]
          bottomright = args[1]
          initialize4(topleft.x, topleft.y, bottomright.x-topleft.x+1, bottomright.y-topleft.y+1)
        end
      else
        xx, yy, ww, hh = args[0], args[1], args[2], args[3]
        initialize4(xx, yy, ww, hh)
      end
    end

    def clone
      FXRectangle.new(x, y, w, h)
    end 

    def ==(other)
      if other.kind_of?(FXRectangle)
        (self.x == other.x) && (self.y == other.y) && (self.w == other.w) && (self.h == other.h)
      else
        false
      end
    end
    
    # Point in rectangle?
    def contains(*args)
      if args.length == 1
        if args[0].kind_of?(FXPoint)
          contains(args[0].x, args[0].y)
        elsif args[0].kind_of?(FXRectangle)
          r = args[0]
          x <= r.x && y <= r.y && r.x+r.w<=x+w && r.y+r.h<=y+h
        else
          raise TypeError, 'expected FXPoint or FXRectangle'
        end
      elsif args.length == 2
        xx, yy = args[0], args[1]
        x <= xx && y <= yy && xx < x+w && yy < y+h
      end
    end
    
    # Rectangles overlap?
    def overlaps?(other)
      if other.kind_of?(FXRectangle)
        self.x<other.x+other.w && self.y<other.y+other.h && other.x<self.x+self.w && other.y<self.y+self.h
      else
        raise TypeError, 'expected another FXRectangle'
      end
    end
    
    # Return moved rectangle
    def move(dx, dy)
      self.x = self.x + dx
      self.y = self.y + dy
      self
    end
    
    # Grow by amount
    def grow(*args)
      if args.length == 1
        margin = args[0]
        grow(margin, margin, margin, margin)
      elsif args.length == 2
        hormargin = args[0]
        vermargin = args[1]
        grow(hormargin, hormargin, vermargin, vermargin)
      else
        leftmargin = args[0]
        rightmargin = args[1]
        topmargin = args[2]
        bottommargin = args[3]
        self.x = self.x - leftmargin
        self.y = self.y - topmargin
        self.w = self.w + (leftmargin + rightmargin)
        self.h = self.h + (topmargin + bottommargin)
      end
      self
    end
    
    # Shrink by amount
    def shrink(*args)
      if args.length == 1
        margin = args[0]
        shrink(margin, margin, margin, margin)
      elsif args.length == 2
        hormargin = args[0]
        vermargin = args[1]
        shrink(hormargin, hormargin, vermargin, vermargin)
      else
        leftmargin = args[0]
        rightmargin = args[1]
        topmargin = args[2]
        bottommargin = args[3]
        self.x = self.x + leftmargin
        self.y = self.y + topmargin
        self.w = self.w - (leftmargin + rightmargin)
        self.h = self.h - (topmargin + bottommargin)
      end
      self
    end
    
    # Corners
    def tl
      FXPoint.new(self.x, self.y)
    end
    
    def tr
      FXPoint.new(self.x+self.w-1, self.y)
    end
    
    def bl
      FXPoint.new(self.x, self.y+self.h-1)
    end
    
    def br
      FXPoint.new(self.x+self.w-1, self.y+self.h-1)
    end
    
    # Union with rectangle
    def +(other)
      if other.kind_of?(FXRectangle)
        xx = [other.x, self.x].min
        ww = [other.x+other.w, self.x+self.w].max - xx
        yy = [other.y, self.y].min
        hh = [other.y+other.h, self.y+self.h].max - yy
        FXRectangle.new(xx, yy, ww, hh)
      else
        raise TypeError, 'expected FXRectangle'
      end
    end
    
    # Intersection with rectangle
    def *(other)
      if other.kind_of?(FXRectangle)
        xx = [other.x, self.x].max
        ww = [other.x+other.w, self.x+self.w].min - xx
        yy = [other.y, self.y].max
        hh = [other.y+other.h, self.y+self.h].min - yy
        FXRectangle.new(xx, yy, ww, hh)
      else
        raise TypeError, 'expected FXRectangle'
      end
    end
  end
  
  #
  # Size
  #
  class FXSize
  
    alias initializeWH initialize
    
    #
    # Returns an initialized FXSize instance.
    #
    def initialize(*args)
      if args.length == 0
        initializeWH(0, 0)
      elsif args.length == 1
        if args[0].kind_of?(FXSize)
          initializeWH(args[0].w, args[0].h)
        else
          raise TypeError, 'expected FXSize'
        end
      else
        initializeWH(args[0], args[1])
      end
    end
    
    def clone
      FXSize.new(w, h)
    end 
    
    #
    # Returns +true+ if the width and height of the _other_ size
    # are equal to this size's width and height.
    #
    def ==(other)
      if other.kind_of?(FXSize)
        (self.w == other.w) && (self.h == other.h)
      else
        false
      end
    end
    
    def -@
      FXSize.new(-self.w, -self.h)
    end
    
    #
    # Returns a new size instance obtained by memberwise
    # addition of the _other_ size instance with this
    # one.
    #
    def +(other)
      if other.kind_of?(FXSize)
        FXSize.new(self.w + other.w, self.h + other.h)
      else
        raise TypeError, 'expected FXSize'
      end
    end
    
    #
    # Returns a new size instance obtained by memberwise
    # subtraction of the _other_ size instance from this
    # one.
    #
    def -(other)
      if other.kind_of?(FXSize)
        FXSize.new(self.w - other.w, self.h - other.h)
      else
        raise TypeError, 'expected FXSize'
      end
    end
    
    #
    # Returns a new size instance obtained by memberwise
    # multiplication of the width and height by _value_.
    #
    def *(value)
      FXSize.new(value*self.w, value*self.h)
    end
    
    #
    # Returns a new size instance obtained by memberwise
    # division of the width and height by _value_.
    #
    def /(value)
      FXSize.new(self.w/value, self.h/value)
    end
  end
  
  class FXDataTarget
    #
    # Returns the stringified representation of this
    # data target's value.
    #
    def to_s
      value.to_s
    end
  end
  
  class FXHeader
    #
    # Returns true if the specified header item's arrow points
    # up. Raises IndexError if _index_ is out of bounds.
    #
    def arrowUp?(index)
      if index < 0 || index >= numItems 
        raise IndexError, "header item index out of bounds"
      else
        getArrowDir(index) == Fox::TRUE
      end
    end

    #
    # Returns true if the specified header item's arrow points
    # down. Raises IndexError if _index_ is out of bounds.
    #
    def arrowDown?(index)
      if index < 0 || index >= numItems 
        raise IndexError, "header item index out of bounds"
      else
        getArrowDir(index) == Fox::FALSE
      end
    end

    #
    # Returns true if the specified header item does not display
    # any arrow. Raises IndexError if _index_ is out of bounds.
    #
    def arrowMaybe?(index)
      if index < 0 || index >= numItems 
        raise IndexError, "header item index out of bounds"
      else
        getArrowDir(index) == Fox::MAYBE
      end
    end
  end

  class FXSettings
    #
    # Read a boolean registry entry from the specified _section_ and _key_.
    # If no value is found, the _default_ value is returned.
    #
    def readBoolEntry(section, key, default=false)
      default = default ? 1 : 0
      readIntEntry(section, key, default) != 0
    end
    
    #
    # Write a boolean registry _value_ to the specified _section_ and _key_.
    #
    def writeBoolEntry(section, key, value)
      writeIntEntry(section, key, value ? 1 : 0)
    end
  end
  
  class FXWindow
    #
    # Iterate over the child windows for this window.
    #
    def each_child
      child = self.first
      while child
        yield child
	child = child.next
      end
    end
  end

  #
  # The drag-and-drop data used for colors is a sequence of unsigned short
  # integers, in native byte ordering. Here, we use the 'S' directive for
  # String#unpack (which treats two successive characters as an unsigned short
  # in native byte order) to decode the R, G, B and A values.
  #
  def Fox.fxdecodeColorData(data)
    clr = data.unpack('S4')
    Fox.FXRGBA((clr[0]+128)/257, (clr[1]+128)/257, (clr[2]+128)/257, (clr[3]+128)/257)
  end
  
end
