export interface IRange {
  start: number
  end: number

  contains(num: number): boolean

  containsRange(other: IRange): boolean

  isContainedInRange(other: IRange): boolean

  strictlyContainsRange(other: IRange): boolean

  isStrictlyContainedInRange(other: IRange): boolean
}

export class Range implements IRange {
  constructor(public start: number, public end: number) {
    if (!isValidRange(start, end)) {
      throw new Error("INVALID RANGE")
    }
  }

  contains(num: number): boolean {
    return this.start <= num && this.end >= num
  }

  containsRange(other: IRange): boolean {
    return this.start <= other.start && this.end >= other.end
  }

  isContainedInRange(other: IRange): boolean {
    return other.containsRange(this)
  }

  strictlyContainsRange(other: IRange): boolean {
    return this.start < other.start && this.end > other.end
  }

  isStrictlyContainedInRange(other: IRange): boolean {
    return other.strictlyContainsRange(this)
  }
}

export function isValidRange(start: number, end: number): boolean {
  return !(start < 0 || end < start)
}
