/*
   Copyright 2010 Aaron J. Radke

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
package cc.drx

import scala.concurrent.duration.{FiniteDuration => ScalaDuration}

object Measure{
   private val prefix:Map[Char,Double] = Map(
         'E' -> 1E18, //exa
         'P' -> 1E15, //peta
         'T' -> 1E12, //tera
         'G' -> 1E9,  //giga
         'M' -> 1E6,  //mega
         'k' -> 1E3,  //kilo
         // 'h' -> 1E2, //hecto
         // 'da' -> 1E1, //deca
         // 'd' -> 1E-1, //deci
         // 'c' -> 1E-2, //centi
         'm' -> 1E-3, //milli
         'u' -> 1E-6, //micro
         'μ' -> 1E-6, //micro
         'n' -> 1E-9, //nano
         'p' -> 1E-12, //pico
         // 'f' -> 1E-15, //femto  //FIXME turn this back after moving to try prefix (the measure)
         'a' -> 1E-18 //atto
   )
   //private def singularize(str:String):String = if((str.size > 1) && (str endsWith "s")) str.dropRight(1) else str
   private val decDigits = ".-+0123456789Ee*".toSet
   def apply(str:String):Measure = {
      val (num,unitTemp) = str span {decDigits contains _}
      val unit = unitTemp.trim
      val value = if(num == "") 1d else num.split('*').foldLeft{1d}{case (v, n) => v*n.toDouble}
      val (scale, baseUnit) = unit.size match {
         case 0 => (1.0,"")
         //case 1 => (prefix get unit(0)) map { _ -> ""} getOrElse (1.0,unit)
         case 2 => (prefix get unit(0)) map { _ -> unit(1).toString } getOrElse Tuple2(1.0,unit)
         case _ => (1.0,unit)
      }
      //println(s"----\nunit:$unit\nscale:$scale\nbaseUnit:$baseUnit")
      Measure(value*scale, baseUnit)
   }
}
case class Measure(value:Double,unit:String){
   def base(units:Map[String,Double]):Double = if(unit=="") value else value*units(unit)
}
trait Units{
   val units:Map[String,Double]
   def parseToBaseValue(str:String):Double = Measure(str) base units
   /**A simple string test to see if the string is defined with valid units*/
   def isDefined(str:String):Boolean = units.keys.exists{str endsWith _}
}
//TODO it feels like there are to many redundant typeclasses around here; Meausre, BaseValue, Unit, BaseValueBuilder; all to support anyval wrapping?
//     maybe make the trait Units into the a typeclass like UnitBuilder
/**typeclass for generic building/(and extracting) basevalues for unit types (essentially a generic way to wrap doubles) */
trait BaseValueBuilder[A]{
//trait BaseValueBuilder[A] extends Boundable[A] /*because doubles are boundable*/ with Parsable[A] /*with required unit string map*/
  //-- required
  def apply(baseValue:Double):A
  def baseValueOf(unit:A):Double
  //-- derived
  //TODO deprecate maybe since use cases should just use the functions directly to remove the expense of creating a function object
  final def map(x:A)(f:Double => Double):A = apply(f(baseValueOf(x)))
}

trait BoundableBaseValue[A <: BaseValue[A]] extends Bound.Boundable[A]{
   def lessThan(a:A,b:A):Boolean =  a.baseValue < b.baseValue
   def interpolate(min:A,max:A, ratio:Double):A = (min lerp max)(ratio)
   def ratioOf(min:A,max:A, x:A):Double = (x.baseValue-min.baseValue)/(max.baseValue-min.baseValue)
   override def dist(min:A,max:A):Double = (max.baseValue - min.baseValue).abs
   override def gain(min:A,max:A):Double = (max.baseValue/min.baseValue).abs
}
//TODO remove this since it is not needed
// trait BaseValueOrdering[A <: BaseValue[A]] extends scala.math.Ordering[A]{
// }

//--- the following provide prepended scaler values but requires the use of
//  import scala.language.implicitConversions
//  at the call site, therefor consider removing
//  note these behave similar to DrxDouble and DrxInt but prevent the need to import the implicit conversionis, but rather simple require the sin tax of language imports
/*
class ScalarDouble(val v:Double){
  def *[A](other:BaseValue[A]):A = other*v
}
object ScalarDouble{
  implicit def fromDouble(v:Double) = new ScalarDouble(v)
}
class ScalarInt(val v:Int){
  def *[A](other:BaseValue[A]):A = other*v
}
object ScalarInt{
  implicit def fromInt(v:Int) = new ScalarInt(v)
}
*/

/**primary base trait for all measurment unit types*/
trait BaseValue[A] extends Any with scala.math.Ordered[A] {
   //---required traits
   def baseValue:Double
   // def baseSymbol:String
   def apply(v:Double):A

   //---derived traits
   def ~(that:A)(implicit b:Bound.Boundable[A]):Bound[A] = Bound(apply(baseValue),that)
   def ~>(that:BaseValue[A])(implicit b:Bound.Boundable[A]):Bound[A] =
     Bound(apply(this.baseValue),apply(this.baseValue+that.baseValue))
   def +-(eps:BaseValue[A])(implicit b:Bound.Boundable[A]):Bound[A] = Bound(apply(baseValue-eps.baseValue) , apply(baseValue+eps.baseValue))
   def ~=(that:BaseValue[A])(implicit eps:Eps):Boolean = math.abs(baseValue-that.baseValue) < eps.v

   def +(that:BaseValue[A])(implicit d1: DummyImplicit):A = apply(this.baseValue + that.baseValue)
   def -(that:BaseValue[A])(implicit d1: DummyImplicit):A = apply(this.baseValue - that.baseValue)
   def /(that:BaseValue[A])(implicit d1: DummyImplicit):Double = this.baseValue/that.baseValue //cancelation

   def *(scale:Double)(implicit d1: DummyImplicit):A = apply(this.baseValue*scale)
   def *(scale:Int)(implicit d1: DummyImplicit):A = apply(this.baseValue*scale.toDouble)
   def *(scale:Long)(implicit d1: DummyImplicit):A = apply(this.baseValue*scale.toDouble)
   def /(scale:Double)(implicit d1: DummyImplicit):A = apply(this.baseValue/scale)
   def /(scale:Int)(implicit d1: DummyImplicit):A = apply(this.baseValue/scale.toDouble)
   def /(scale:Long)(implicit d1: DummyImplicit):A = apply(this.baseValue/scale.toDouble)

   def unary_- :A = apply(-this.baseValue)
   def abs:A = apply(this.baseValue.abs)
   def compare(that:BaseValue[A]):Int = this.baseValue compare that.baseValue

   def lerp(that:BaseValue[A])(ratio:Double):A =
      apply(this.baseValue + ratio*(that.baseValue-this.baseValue) )

   //TODO 2017-07-30("should be format instead","v0.2.15")
   def nice:String
}
object Time extends Units{
   private val sPerHr:Double = 3600
   private val sPerDay:Double = 3600*24
   private val sPerYr:Double = 3600*24*365.242198781   //this is the definition of a true year averaged over time
   private val sPerWk:Double = sPerDay*7
   private val sPerMo:Double = sPerYr/12

   //val NANOSECONDS = java.util.concurrent.TimeUnit.NANOSECONDS
   private lazy val timer = new java.util.Timer(true)
   private val ms0 = Date.now.ms
   private[drx] def initMs = Date.now.ms - ms0

   val units:Map[String,Double] = Map(
      "s"       -> 1,
      "sec"     -> 1,
      "second"  -> 1,

      "ms"      -> 1E-3,
      "us"      -> 1E-6,
      "μs"      -> 1E-6,
      "ns"      -> 1E-9,
      "ps"      -> 1E-12,
      "fs"      -> 1E-15,

      "m"       -> 60,
      "min"     -> 60,
      "minute"  -> 60,

      "h"       -> 3600,
      "hr"      -> 3600,
      "hour"    -> 3600,

      "d"       -> sPerDay,
      "day"     -> sPerDay,

      "w"       -> sPerWk,
      "wk"      -> sPerWk,
      "week"    -> sPerWk,

      "mo"      -> sPerMo,
      "mon"     -> sPerMo,
      "month"   -> sPerMo,

      "y"       -> sPerYr,
      "yr"      -> sPerYr,
      "year"    -> sPerYr,  //tropical year (vernal equinox mean)

      "siderealyear"  -> sPerDay*365.256360417,  //1 time around the sun

      "commonyear" -> sPerDay*365,
      "leapyear"   -> sPerDay*366,

      "decade"  -> sPerYr*10,

      "century" -> sPerYr*100,

      "kyr"       -> sPerYr*1000,
      "millenium" -> sPerYr*1000,

      "Gyr"       -> sPerYr*1E9,
      "Gy"        -> sPerYr*1E9
   )
   private val formatLookup:Array[(Time,String)] = "Gyr kyr century yr mon wk day hr min s ms us ns ps fs".split(' ').map{k => (Time(units(k)),k)}
   def apply(str:String):Time = Time(parseToBaseValue(str))
   def apply(value:Double,unit:String):Time = Time(value*parseToBaseValue(unit))
   def apply(value:Long,unit:String):Time = Time(value.toDouble*parseToBaseValue(unit))
   def apply(bound:Bound[Date]):Time = Time(math.abs(bound.max.ms - bound.min.ms)*1E-3)

   def apply(duration:ScalaDuration):Time = Time(duration.toNanos/1E9)

   implicit object BoundableTime extends BoundableBaseValue[Time]
   implicit object ParsableTime extends Parsable[Time]{ def apply(v:String):Time = Time(v) }
   implicit object BaseValueBuilderTime extends BaseValueBuilder[Time]{
     def apply(baseValue:Double):Time = Time(baseValue)
     def baseValueOf(unit:Time):Double = unit.baseValue
   }

   // TODO remove this implict conversion and put this in the package like predef
   import scala.language.implicitConversions
   implicit def drxTime2ScalaDuration(time:Time):ScalaDuration = time.asScala
   implicit def scalaDuration2DrxTime(duration:ScalaDuration):Time = Time(duration)

   def format(dt:Time,numDecimals:Int):Format[Time] = new Format[Time]{
     val dt0 = dt.abs
     val (base,unit) = Time.formatLookup.find(dt0 >= _._1) getOrElse Time.formatLookup.last
     val fmt = s"%.${numDecimals}f${unit}"

     override def apply(t:Time):String = fmt.format(t/base)
   }

   val ms   = Time(1.0/1000)
   val min  = Time(60)
   val hr   = Time(3600)
   val day  = Time(3600*24)
   val yr   = Time(sPerYr)
   val month = Time(sPerMo)
}
case class Time(s:Double) extends AnyVal with BaseValue[Time]{
   def as(unit:String):Double = s/Time.parseToBaseValue(unit)

   def baseValue = s
   // def baseSymbol = "s"
   def apply(v:Double):Time = Time(v)

   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Time):Int = this.baseValue compare that.baseValue

   //**convenience function for milliseconds*/
   def ms   = s*1E3
   def us   = s*1E6
   def ns   = s*1E9
   def min  = s/60
   def minute  = s/60
   def hr   = s/3600
   def day  = s/(3600*24)
   def month = s/(3600*24*365.242198781/12)
   def yr   = s/(3600*24*365.242198781)

   //easy date construction from runtime date with rounding (like rails)
   def ago:Date = (Date.now - this)//TODO add rounding

   2017-07-30("use `asScala` instead","dk")
   def toDuration:ScalaDuration = asScala

   import java.util.concurrent.TimeUnit.NANOSECONDS
   def asScala:ScalaDuration = new ScalaDuration(ns.toLong,NANOSECONDS) //use nanos for more precision

   //note: the cc.drx.ScheduledContext is used here instead the aliased java.util.concurrent.ScheduledThreadPoolExecutor to provide a more drx focused implicit not found message provided in the cc.drx package object
   import cc.drx.{ScheduledContext => SC} //using this alias for schedule executor provides better missing implicit warning messagse than the one for java
   def delay[A](f: => A)(implicit ex:SC):Future[A] = Repeater.delay(this, f)
   def repeat(f: => Unit)(implicit ex:SC) = Repeater.repeat(this, None, f)
   def repeat(timeout:Time)(f: => Unit)(implicit ex:SC) = Repeater.repeat(this, Some(timeout), f)
   def repeatSpaced(f: => Unit)(implicit ex:SC) = Repeater.repeatSpaced(this,None, f)


   override def toString = s"Time($format)"

   def inv:Frequency = Frequency(1.0/s)

   /** t*f = [s][hz] = [s][1/s] = [1] */
   def *(freq:Frequency):Double = s*freq.hz

   //TODO maybe deprecate with round(dt) and format(dt)
   2017-07-30("use format instead","v0.2.15")
   def nice = format

   //use the current time as a scale for the time rounding like nice but as time
   // TODO remove def round:Time = round(Tick.TickTime.delta(this))
   def round(dt:Time):Time = dt.abs*(this/dt.abs).round //it is important to make sure signs are conserved correctly
   def format:String = format(this,1)
   def format(numDecimals:Int):String = format(this,numDecimals)
   def format(dt:Time,numDecimals:Int):String = Time.format(dt,numDecimals)(this)

   /**triangular wave from 0 to 1*/
   def ramp:Double = (Time.initMs % ms)/ms
   /**sinusoidal wave from 0 to 1*/
   def cycle:Double = ((ramp*tau).sin+1)/2

   /**An easy to use sleep function directly on the time object but always prints a warning suggesting not to use this method*/
   def sleep:Unit = sleepWithOptionalWarning(true)
   /**A sleep function directly on the time that looks ugly in code but doesn't look ugly at run time (assuming you meant this)*/
   def sleepWithoutWarning():Unit = sleepWithOptionalWarning(false)
   private def sleepWithOptionalWarning(showWarning:Boolean):Unit = if(s <= 0d) () else { //skip any thread generation if sleep time is zero
     val thread = Thread.currentThread
     val group  = thread.getThreadGroup
     if(showWarning) Console.err.println(s"Warning: $format.sleep is blocking thread:${thread.getName} in group:${group.getName}")
     Thread.sleep(ms.round.toLong)
   }

   //TODO replace the following sleep based loops with this schedule based delays from the Repeater
   //experimental features, may offer better return options than Unit, but safely wrap some while loops for world time
   def loop(f: => Unit):Unit = {
     val ns0 = System.nanoTime
     val nsEnd = ns.toLong
     while(System.nanoTime - ns0 < nsEnd){ f }
   }
   def loopWithIndex(f: Long => Unit):Unit = {
     val ns0 = System.nanoTime
     val nsEnd = ns.toLong
     var i = 0L
     while(System.nanoTime - ns0 < nsEnd){
       f(i)
       i += 1
     }
   }
   def iterate[A](init:A)(f:A => A):A = {
     val ns0 = System.nanoTime
     val nsEnd = ns.toLong
     var acc = init
     while(System.nanoTime - ns0 < nsEnd){ acc = f(acc) }
     acc
   }

   /**bandwidth frequency, based on the first order filter based rise time-constant,
    * the bandwith of a time-constant rise time is roughly:
    * ω  = 2πf = 4/tr
    * tr = 4/ω  = 4/(2πf)
    * f  = 4/(2π*tr)
    */
   def bandwidth:Frequency = Frequency(4d / (2*pi*s) )
}
object Angle extends Units{
   val units:Map[String,Double] = Map(
      //"r"       -> 1,
      "rad"     -> 1,
      "radian"  -> 1,

      "π"       -> math.Pi,
      "Pi"      -> math.Pi,

      "τ"       -> 2*math.Pi,
      "tau"     -> 2*math.Pi,

      //"d"       -> math.Pi/180,
      "deg"     -> math.Pi/180,
      "°"       -> math.Pi/180,

      //"m"       -> math.Pi/180/60,
      "min"     -> math.Pi/180/60,
      "'"       -> math.Pi/180/60,

      "s"       -> math.Pi/180/3600,
      "sec"     -> math.Pi/180/3600,
      "\""      -> math.Pi/180/3600
   )
   def apply(str:String):Angle = Angle(parseToBaseValue(str))
   def apply(value:Double,unit:String):Angle = Angle(value*parseToBaseValue(unit))
   def apply(deg:Double,min:Double,sec:Double):Angle = {
     val sgn = if(deg != 0) deg.sgn else if(min != 0) min.sgn else sec.sgn
     Angle(sgn*(deg.abs + min.abs/60.0 + sec.abs/3600.0)*math.Pi/180.0)
   }

   lazy val full = Angle(2*math.Pi)
   lazy val half = Angle(math.Pi)
   lazy val quarter = Angle(math.Pi/2)
   //def apply(rad:Double):Angle = new Angle(rad) //math.atan2(math.sin(rad), math.cos(rad))
   //def apply(rad:Double):Angle = new Angle(math.cos(rad), math.sin(rad)) //math.atan2(math.sin(rad), math.cos(rad))
   //def apply(x:Double,y:Double):Angle = new Angle(x,y)
   //def apply(v:Vec):Angle = new Angle(v.x,v.y)

   implicit object BoundableAngle extends BoundableBaseValue[Angle]{
     /* TODO remove the following if they are not needed (in the past Arc used these special cases for a test
      override def norm(b:Bound[Angle]):Bound[Angle] = {
         val m = b.min.norm
         val M = b.max.norm
         if(m > M) Bound(m-full,M) else Bound(m,M)
      }
      override def containsNorm(b:Bound[Angle],x:Angle):Boolean = {
         val xnorm = x.norm
         (b.norm.min < xnorm && xnorm < b.norm.max) ||
         {val xadj = xnorm-full; (b.norm.min < xadj && xadj < b.norm.max)}
      }
      */
   }
   implicit object ParsableAngle extends Parsable[Angle]{ def apply(v:String):Angle = Angle(v) }
}
case class Angle(rad:Double) extends AnyVal with BaseValue[Angle]{
   def as(unit:String):Double = rad/Angle.parseToBaseValue(unit)
   def deg = rad*rad2deg
   2017-07-30("use norm instead","0.2.5")
   def pos  = if(rad < 0) Angle(rad + tau) else this
   def norm = {val r = rad % tau; if(r < 0) Angle(r + tau) else Angle(r)}

   def baseValue = rad
   // def baseSymbol = "rad"
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Angle):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Angle(v)

   override def toString = s"Angle($nice)"

   def degMinSec:(Int,Int,Double) = {
      val dd = deg.abs
      val d = dd.toInt
      val t1 = (dd - d)*60
      val m = t1.toInt
      val s = (t1 - m) * 60
      (deg.sgn.toInt*d, m, s)
   }
   def degMinSecString:String = {
      val (d,m,s) = degMinSec
      s"$d°$m\'${s.round.toInt}" + '"'
   }

   def delta(that:Angle):Angle = Vec.angle(this).rz(-that).heading
   def rzDelta(that:Angle):Angle = {
      val r = this-that
      if (r < Angle(0)) (that-this-Angle.full).abs else r
   }

   //def ciѕ:Vec = Vec(cos,sin)   //cis and unit should be equvilante
   //def unit:Vec = Vec.angle(rad)

   def cos:Double = math.cos(rad)
   def sin:Double = math.sin(rad)
   def tan:Double = math.tan(rad)

    def sin2 = sin.sq//{val t = math.sin(rad); t*t}
    def cos2 = cos.sq//{val t = math.cos(rad); t*t}
    def tan2 = tan.sq//{val t = math.tan(rad); t*t}

   def nice = s"${deg}deg"
}
object Frequency extends Units{
   val units:Map[String,Double] = Map(
      "Hz"       -> 1,
      "hz"       -> 1,
      "rpm"      -> 60,  //rev per minute
      "dpm"      -> 360*60 //deg per minute
   )
   def apply(str:String):Frequency = Frequency(parseToBaseValue(str))
   def apply(value:Double,unit:String):Frequency = Frequency(value*parseToBaseValue(unit))

   implicit object BoundableFrequency extends BoundableBaseValue[Frequency]
   implicit object ParsableFrequency extends Parsable[Frequency]{ def apply(v:String):Frequency = Frequency(v) }
}
case class Frequency(hz:Double) extends AnyVal with BaseValue[Frequency]{
   def as(unit:String):Double = hz/Frequency.parseToBaseValue(unit)

   def baseValue = hz
   // def baseSymbol = "Hz"
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Frequency):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Frequency(v)

   override def toString = s"Frequency($nice)"

   def inv:Time = Time(1.0/hz)

   /** f*t = [hz][s] = [1/s][s] = [1] */
   def *(time:Time):Double = hz*time.s

   /**angular frequency omega = ω = 2πf */
   def omega = 2*pi*hz

   def nice = s"${hz}Hz"
}
object Length extends Units{
   val units:Map[String,Double] = Map(
      "m"       -> 1,
      "meter"   -> 1,

      "nmi"   -> 1852,
      "nauticalmile" -> 1852,

      "mile"    -> 1609.344,

      "yd"      -> 0.9144,
      "yard"    -> 0.9144,

      "ft"      -> 0.3048,
      "feet"    -> 0.3048,
      "foot"    -> 0.3048,

      "in"      -> 0.0254,
      "inch"    -> 0.0254
   )
   def apply(str:String):Length = Length(parseToBaseValue(str))
   def apply(value:Double,unit:String):Length = Length(value*parseToBaseValue(unit))

   implicit object BoundableLength extends BoundableBaseValue[Length]
   implicit object ParsableLength extends Parsable[Length]{def apply(v:String):Length = Length(v) }
}
case class Length(m:Double) extends AnyVal with BaseValue[Length]{
   def as(unit:String):Double = m/Length.parseToBaseValue(unit)

   def baseValue = m
   // def baseSymbol = "m"
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Length):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Length(v)

   override def toString = s"Length($nice)"

   def /(t:Time):Velocity = Velocity(m/t.s)
   def /(v:Velocity)(implicit d1: DummyImplicit, d2: DummyImplicit):Time = Time(m/v.base)   //DummyImplicit trick to get around similar method signatures for Time&Velocity value types

   def ft = m/0.3048

   def nice = s"${m}m"

   def north = Ned(this, 0.m, 0.m)
   def east  = Ned(0.m, this, 0.m)
   def down  = Ned(0.m,  0.m, this)
}
object Mass extends Units{
   val units:Map[String,Double] = Map(
      "kg"     -> 1,

      "g"      -> 1E-3,
      "gram"   -> 1E-3,

      "pound"  -> 0.45359237,
      "lb"     -> 0.45359237,

      "slug"   -> 0.06852178,  //14.59390 kg

      "ounce"  -> 0.0283495,
      "oz"     -> 0.0283495,

      "tonne"  -> 0.0001, //metric ton
      "ton"    -> 0.0011023 // us-ton is 2000lb //short ton //FYI lots of confusion for these terms of ton
   )
   def apply(str:String):Mass = Mass(parseToBaseValue(str))
   def apply(value:Double,unit:String):Mass = Mass(value*parseToBaseValue(unit))
   implicit object BoundableMass extends BoundableBaseValue[Mass]
   implicit object ParsableMass extends Parsable[Mass]{def apply(v:String):Mass = Mass(v)}
}
case class Mass(kg:Double) extends AnyVal with BaseValue[Mass]{
   def as(unit:String):Double = kg/Mass.parseToBaseValue(unit)

   def baseValue = kg
   // def baseSymbol = "kg"
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Mass):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Mass(v)

   override def toString = s"Mass($nice)"

   def nice = s"${kg}kg"
}

object Velocity extends Units{
   val units:Map[String,Double] = Map(
      "m/s"     -> 1,
      "knot"    -> 0.514444,
      "kt"      -> 0.514444,
      "mph"     -> 0.44704,
      "fps"     -> 0.3048,
      "ft/s"    -> 0.3048,
      "fpm"     -> 0.00508,
      "kph"     -> 0.277778
   )
   def apply(str:String):Velocity = Velocity(parseToBaseValue(str))
   def apply(value:Double,unit:String):Velocity = Velocity(value*parseToBaseValue(unit))
   implicit object BoundableVelocity extends BoundableBaseValue[Velocity]
   implicit object ParsableVelocity extends Parsable[Velocity]{ def apply(v:String):Velocity = Velocity(v) }
}
case class Velocity(base:Double) extends AnyVal with BaseValue[Velocity]{
   def as(unit:String):Double = base/Velocity.parseToBaseValue(unit)

   def baseValue = base
   // def baseSymbol = "m/s"
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Velocity):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Velocity(v)

   override def toString = s"Velocity($nice)"

   def *(t:Time):Length = Length(base*t.s)
   def /(t:Time):Acceleration = Acceleration(base/t.s)

   def nice = s"${base}m/s"
}
object Acceleration extends Units{
   val gravity = Acceleration(0.10197162129)
   val units:Map[String,Double] = Map(
      "m/s^2"   -> 1.0,
      "m/s/2"   -> 1.0,
      "ft/s^2"  -> 0.3048,
      "ft/s/s"  -> 0.3048,
      "g0"      -> 0.10197162129,
      "g's"     -> 0.10197162129,
      "gravity" -> 0.10197162129
   )
   def apply(str:String):Acceleration = Acceleration(parseToBaseValue(str))
   def apply(value:Double,unit:String):Acceleration = Acceleration(value*parseToBaseValue(unit))
   implicit object BoundableAcceleration extends BoundableBaseValue[Acceleration]
   implicit object ParsableAcceleration extends Parsable[Acceleration]{ def apply(v:String):Acceleration = Acceleration(v) }
}
case class Acceleration(base:Double) extends AnyVal with BaseValue[Acceleration]{
   def as(unit:String):Double = base/Acceleration.parseToBaseValue(unit)

   def baseValue = base
   // def baseSymbol = "m/s^2"
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Acceleration):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Acceleration(v)

   override def toString = s"Acceleration($nice)"

   def *(t:Time):Velocity = Velocity(base*t.s)
   def *(m:Mass)(implicit d1: DummyImplicit, d2: DummyImplicit):Force = Force(base*m.kg)   //DummyImplicit trick to get around similar method signatures for Time&Velocity value types

   def nice = s"${base}m/s"
}
object Force extends Units{
   val units:Map[String,Double] = Map(
      "N"        -> 1.0,
      "kg*m/s^2" -> 1.0,
      "lbf"      -> 0.224809
   )
   def apply(str:String):Force = Force(parseToBaseValue(str))
   def apply(value:Double,unit:String):Force = Force(value*parseToBaseValue(unit))
   implicit object BoundableForce extends BoundableBaseValue[Force]
   implicit object ParsableForce extends Parsable[Force]{ def apply(v:String):Force = Force(v) }
}
case class Force(base:Double) extends AnyVal with BaseValue[Force]{
   def as(unit:String):Double = base/Force.parseToBaseValue(unit)

   def baseValue = base
   // def baseSymbol = "N" //"kg*m/s^2" 
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Force):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Force(v)

   override def toString = s"Force($nice)"

   def /(m:Mass):Acceleration = Acceleration(base/m.kg)

   def nice = s"${base}m/s"
}
object Energy extends Units{
   val units:Map[String,Double] = Map(
      "J"          -> 1.0,
      "kg*m^2/s^2" -> 1.0,
      "kg*m*m/s/s" -> 1.0,

      "kWh"        -> 2.77778e-7, //kWh = 3.6E6J

      "hph"        -> 3.72508847e-7, //horsepower hour = 2.6845 MJ
      "eV"         -> 6.2415095e+18 //ev = 1.60217653E-19J
   )
   def apply(str:String):Energy = Energy(parseToBaseValue(str))
   def apply(value:Double,unit:String):Energy = Energy(value*parseToBaseValue(unit))
   implicit object BoundableEnergy extends BoundableBaseValue[Energy]
   implicit object ParsableEnergy extends Parsable[Energy]{ def apply(v:String):Energy = Energy(v) }
}
case class Energy(base:Double) extends AnyVal with BaseValue[Energy]{
   def as(unit:String):Double = base/Energy.parseToBaseValue(unit)

   def baseValue = base
   // def baseSymbol = "N" //"kg*m/s^2" 
   //why is this needed ??? when it already lives in the BaseValue trait?
   def compare(that:Energy):Int = this.baseValue compare that.baseValue
   def apply(v:Double) = Energy(v)

   override def toString = s"Energy($nice)"

   def nice = s"${base}m/s"
}
//TODO add,,, this shows a better mechanism is required...
//Area
//Volume
//Density



object Bytes{
  def bits(bitCount:Long) = Bytes(bitCount divCeil 8)
}
case class Bytes(byteCount:Long) extends AnyVal with Ordered[Bytes]{
   // def B = size
   2017-07-30("use `byteCount` instead","v0.2.15")
   def size = byteCount
   def bits = byteCount*8
   override def toString = if(byteCount < 1024) s"$byteCount B" else {
      val exp = (byteCount.log/1024.log).toInt //exp index trick hint from aioobe at stackoverflow
      f"${byteCount/(1024d**exp)}%.1f ${"kMGTPE"(exp-1)}B"
   }
   // import scala.math.Ordered.orderingToOrdered
   def compare(that: Bytes):Int = this.byteCount compare that.byteCount
   def +(that:Bytes):Bytes = Bytes(this.byteCount + that.byteCount)
   def -(that:Bytes):Bytes = Bytes(this.byteCount - that.byteCount)
   def *(x:Int):Bytes = Bytes(this.byteCount*x)
   def /(x:Int):Bytes = Bytes(this.byteCount/x)
}