#!/usr/bin/env scalas

// https://gist.github.com/Schnouki/5028480

/***

scalaVersion := "2.11.5"

libraryDependencies ++= Seq(
  "org.apache.commons" % "commons-imaging" % "1.0-SNAPSHOT")

*/

import java.io.FileInputStream

val CONTAINER_ATOMS = Seq("moov", "trak", "mdia")
// Also containers (but not interesting): "minf", "dinf", "stbl"

case class Atom(length: Int, 
  parser: ByteBuffer => Seq[String], 
  labels: Seq[String], 
  offsets: Seq[Int])

val ATOMS = Map(
  "pnot" -> Atom(), 
  "mvhd" -> Atom(), 
  "tkhd" -> Atom(), 
  "mdhd" -> Atom())


class Mov(fn: File) {

  var offets = 0
  private[this] lazy val _f = new FileInputStream(fn).getChannel

  def parse(): Unit = {
    val fsize = _f.size()
    val megabytes = fsize / (math.pow(1024, 2))
    println(s"File: $fn ($fsize bytes, $megabytes MB)")
    _parse(fsize)
  }

  def _parse(length: Long, depth: Int = 0): Unit = {
    val prefix = "  " * depth + "- "
    var n = 0
    while (n < length) {
      val data = CharBuffer.allocate(8)
      val c = _f.read(data)
      if (c <= 0) {
        println("FINISHED")
      }
      else {
        val an = data.toString()
        val al = data.length()
        println(s"${prefix}Atom: $an ($al bytes)")

        if (ATOMS.contains(an)) _parseAtom(an, al - 8, depth)
        else if (an == "udta") _parseUdta(al - 8, depth)
        else if (an == "ftyp") _readFtyp(al - 8, depth)
        else if (CONTAINER_ATOMS.contains(an)) _parse(al - 8, depth + 1)
        else _f.position(_f.position() + 8)
        n = n + al
      }
    }
  }

  def _parseAtom(atom: String, length: Int, depth: Int): Unit = {
    val spec = ATOMS(atom)
    require(length == spec.length)
    val pos = _f.position()
    val prefix = "  " * depth + "  | "
    val b = ByteBuffer.allocate(length)
    _f.read(b)
    val v = spec.parser(b)
    val k = spec.labels
    for (i <- 0 to k.size) {
      val vv = v(i)
      println(s"${prefix}${k(i)}: $vv")
    }
    for (offset <- spec.offsets) {
      offsets = pos + offset
    }
  }

  def _readFtyp(length: Int, depth: Int): Unit = {
    val prefix = "  " * depth + "  | "
    val charsetDecoder = Charset.forName("latin1").newDecoder()
    val data = ByteBuffer.allocate(8)

  }



}