import "math/vector" for Vector
import "luxe: math" for Math
import "math/repVal" for RepVal
import "math/Util" for Util

class M{
  static inv_lerp(from, to, value){
    //if the range are numbers, we assume the interpolation value is too
    if(from is Num && to is Num) return (value - from) / (to - from)
    //if only one of the range qualifiers is a sequence, we make the other one a endless sequence of itself 
    //(will do a union to take the shortest length anyways)
    if(from is Sequence != to is Sequence) {
      if(from is Sequence){
        to = RepVal.new(to)
      } else {
        from = RepVal.new(from)
      }
    }
    //if the interpolation value is a number, make it infinite
    if(value is Num) value = RepVal.new(value)

    var result = []
    Util.for_all([from, to, value]) { |from, to, value|
      result.add(inv_lerp(from, to, value))
    }
    return result
  }

  static lerp(from, to, value){
    //if the range are numbers, we assume the interpolation value is too
    if(from is Num && to is Num) return from + (to - from) * value
    //if only one of the range qualifiers is a sequence, we make the other one a endless sequence of itself 
    //(will do a union to take the shortest length anyways)
    if(from is Sequence != to is Sequence) {
      if(from is Sequence){
        to = RepVal.new(to)
      } else {
        from = RepVal.new(from)
      }
    }
    //if the interpolation value is a number, make it infinite
    if(value is Num) value = RepVal.new(value)

    var result = []
    Util.for_all([from, to, value]) { |from, to, value|
      result.add(lerp(from, to, value))
    }
    return result
  }

  static remap(min_in, max_in, min_out, max_out, value){
    var inter = inv_lerp(min_in, max_in, value)
    return lerp(min_out, max_out, inter)
  }

  static clamp(value, min, max){
    //if its a simple number, we assume so are the bounds
    if(value is Num){
      return Math.max(Math.min(value, max), min)
    }

    //otherwise we assume its a sequence
    //if bounds are numbers, just use them
    if(min is Num && max is Num){
      return value.map {|val| clamp(val, min, max)}.toList
    }
    if(min is Sequence && max is Sequence){
      var result = []
      Util.for_all([value, min, max]) { |v|
        result.add(clamp(v[0], v[1], v[2]))
      }
      return result
    }
    
    System.print("can't clamp %(value.type) between %(min.type) and %(max.type)")
    return null
  }
}