/*
   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

//to be determined essential features of a dynamic Sketch with functions of functions aggregated
trait Sketch extends Shape{  //whoah a Sketch can itself be a shape! nice composability
  private val drawMap:TrieMap[Int, DrawContext => Unit] = TrieMap.empty

  // TODO  make the drawFunction fundemental type first class so a reference id can be used grab it from the graph
  // TODO  make the drawContext return a shape that should be drawn if nothing then UnitShape
  /**safely add new draw functions*/
  //private def unitize(f:DrawContext => Unit):DrawContext => Shape = {g:DrawContext => f(g); Shape.empty}
  ////deprecated("use +=(DrawContext => Shape) intead to encourage functional notions")
  //final def +=(f:DrawContext => Unit):Sketch = {drawMap += (drawMap.size -> unitize(f)); this}
  final def +=(f:DrawContext => Unit):Sketch = {drawMap += (drawMap.size -> f); this}
  // /**alias to safely add new draw functions*/
  // final def add(f:DrawContext => Unit):Sketch = this += f

  final def :=(f:DrawContext => Unit):Sketch = {clear; +=(f)}

  /**remove all draw functions */
  final def clear:Unit = drawMap.clear()

  /**safely access the iterator over all drawFunctions*/
  final def drawFunctions = drawMap.values

  /**the interface of any Shape that can be sent to a render
   * the fact that a Sketch itself can be a shape provides nice composability
   * */
  final def draw(implicit g:DrawContext):Unit = g ! this
}

// FIXME  figure out how to make this work easily with some implicit rendercontext again
// object Sketch{
//   def apply(title:String)(implicit sketchApp:SketchApp):Sketch = ???
// }

abstract class SketchApp extends Sketch {
  //--override-able
  def size:Vec = Vec(600,400)
  def title:String = super.toString.takeWhile(_ != '$').reverse.takeWhile(_ != '.').reverse //"cc.drx.SketchApp"
  def icon:ImgFile = Img find File(title + ".png") getOrElse Img("drx.png")
  def maxFPS:Option[Int] = Some(60)
  def transparent:Boolean = false
  def clearEachFrame:Boolean = true
  def background:Color = Transparent

  override def toString:String = s"Sketch($title, $size)"

  protected[drx] var _args:Array[String] = Array()
  def args:Array[String] = _args

  //--sketch function
  /** alias to '+=' (add) a draw function, this is a helper function to reduce boiler plate; (adds return of unit ()) when only a single draw funtion is desired in an automatic app*/
  // 2017-07-30("TODO remove in favor of '+=' to make the scala collections like to lead to the scala collections like interface","dk")
  final def onDraw(f:DrawContext => Unit):Unit = {clear; this += f; ()}

  /**alias to this so a SketchApp can be easily and automatically constructed*/
  def sketch:SketchApp = this

  //--implemented
  def main(args:Array[String]):Unit = {_args = args; launch(args)} //singleton launcher..

  final def launch(implicit ec:ExecutionContext):Future[Unit] = Future(launch(Array[String]()))(ec)
  final def launch():Future[Unit] = launch(Implicit.ec)

  //--required
  def launch(args:Array[String]):Unit //= ??? //FIXME add a default java implementation or make this a trait

}