require_relative "semantic_version"

class VersionCut
  attr_accessor :semver, :value

  def initialize(value, segments = nil)
    @value = value.to_s
    if segments.nil?
      @semver = SemanticVersion.new(@value)
    else
      @semver = SemanticVersion.new(@value, segments)
    end
  end

  def to_s
    @value.to_s
  end

  def diff(other_cut, abs = true)
    if other_cut.instance_of?(BelowAll)
      AboveAll.new()
    elsif other_cut.instance_of?(AboveAll)
      BelowAll.new()
    else
      diff = self.semver.diff(other_cut.semver, abs)
      if diff.nil?
        EmptyInterval.new()
      else
        VersionCut.new(diff.join("."), diff)
      end
    end
  end

  def is_successor_of?(other_cut)
    return true if other_cut.instance_of?(BelowAll)
    return false if other_cut.instance_of?(AboveAll)

    self.semver.is_successor_of?(other_cut.semver)
  end

  def <(other_cut)
    other_cut.instance_of?(BelowAll) ? false : other_cut.instance_of?(AboveAll) ? true : @semver < other_cut.semver
  end

  def >(other_cut)
    other_cut.instance_of?(BelowAll) ? true : other_cut.instance_of?(AboveAll) ? false : @semver > other_cut.semver
  end

  def <=(other_cut)
    self < other_cut || self == other_cut
  end

  def >=(other_cut)
    self > other_cut || self == other_cut
  end

  def ==(other_cut)
    # self cannot be BelowAll or AboveAll
    if other_cut.instance_of?(BelowAll) || other_cut.instance_of?(AboveAll)
      false
    else
      @semver == other_cut.semver
    end
  end

  def !=(other_cut)
    # self cannot be BelowAll or AboveAll
    if other_cut.instance_of?(BelowAll) || other_cut.instance_of?(AboveAll)
      false
    else
      @semver != other_cut.semver
    end
  end

  def is_initial_version?
    @semver.is_zero?
  end

  def major
    @semver.major
  end

  def minor
    @semver.minor
  end

  def patch
    @semver.patch
  end

  def cross_total
    [minor, major, patch].reject { |i| i.empty? }.map { |i| i.to_i }.inject(0) { |sum, x| sum + x }
  end
end

class BelowAll < VersionCut
  def initialize()
  end

  def to_s
    "-inf"
  end

  def is_initial_version?
    false
  end

  def <(other_cut)
    other_cut.instance_of?(BelowAll) ? false : true
  end

  def >(other_cut)
    false
  end

  def <=(other_cut)
    self < other_cut || self == other_cut
  end

  def >=(other_cut)
    self > other_cut || self == other_cut
  end

  def ==(other_cut)
    (other_cut.instance_of? BelowAll) ? true : false
  end

  def !=(other_cut)
    !(self == other_cut)
  end

  def is_successor_of?(other_cut)
    false
  end
end

class AboveAll < VersionCut
  def initialize()
  end

  def to_s
    "+inf"
  end

  def is_initial_version?
    false
  end

  def <(other_cut)
    false
  end

  def >(other_cut)
    other_cut.instance_of?(AboveAll) ? false : true
  end

  def <=(other_cut)
    self < other_cut || self == other_cut
  end

  def >=(other_cut)
    self > other_cut || self == other_cut
  end

  def ==(other_cut)
    (other_cut.instance_of? AboveAll) ? true : false
  end

  def !=(other_cut)
    !(self == other_cut)
  end

  def is_successor_of?(other_cut)
    !other_cut.instance_of?(AboveAll)
  end
end
