/*
NAME
  RtpToTsConverter.go - provides utilities for the conversion of Rtp packets
  to equivalent MpegTs packets.

DESCRIPTION
  See Readme.md

AUTHOR
  Saxon Nelson-Milton <saxon.milton@gmail.com>

LICENSE
  RtpToTsConverter.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)

  It is free software: you can redistribute it and/or modify them
  under the terms of the GNU General Public License as published by the
  Free Software Foundation, either version 3 of the License, or (at your
  option) any later version.

  It is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 for more details.

  You should have received a copy of the GNU General Public License
  along with revid in gpl.txt.  If not, see [GNU licenses](http://www.gnu.org/licenses).
*/

package parser

import (
  _"fmt"
  "os"

  //"bitbucket.org/ausocean/av/mpegts"
  //"bitbucket.org/ausocean/av/rtp"
  //"bitbucket.org/ausocean/av/tools"
  //"bitbucket.org/ausocean/av/itut"
  "../mpegts"
  "../rtp"
  "../tools"
  "../itut"
)

type RtpToH264Converter interface {
  Convert()
}

type rtpToH264Converter struct {
  TsChan <-chan *mpegts.MpegTsPacket
  tsChan chan<- *mpegts.MpegTsPacket
  InputChan chan<- rtp.RtpPacket
  inputChan <-chan rtp.RtpPacket
  currentTsPacket *mpegts.MpegTsPacket
  payloadByteChan chan byte
  currentCC byte
}

//func parseH264File()
func NewRtpToH264Converter() (c *rtpToH264Converter) {
  c = new(rtpToH264Converter)
  tsChan := make(chan *mpegts.MpegTsPacket,100)
  c.TsChan = tsChan
  c.tsChan = tsChan
  inputChan := make(chan rtp.RtpPacket,100)
  c.InputChan = inputChan
  c.inputChan = inputChan
  c.currentCC = 0
  return
}

func (c* rtpToH264Converter) Convert() {
  file,_ := os.Create("video")
  var rtpBuffer [](*rtp.RtpPacket)
  for {
    select {
    default:
    case rtpPacket := <-c.inputChan:
      rtpBuffer = append(rtpBuffer,&rtpPacket)
      if len(rtpBuffer) > 2 {
        // if there's something weird going on with sequence numbers then sort
        if rtpPacket.SequenceNumber < rtpBuffer[len(rtpBuffer)-2].SequenceNumber {
          for i := 1; i < len(rtpBuffer); i++ {
            for j := i; j > 0 && rtpBuffer[j].SequenceNumber < rtpBuffer[j - 1].SequenceNumber; j-- {
              temp := rtpBuffer[j]
              rtpBuffer[j] = rtpBuffer[j-1]
              rtpBuffer[j-1] = temp
            }
          }
        }
      }
      if len(rtpBuffer) > 200 {
        // Discard everything before a type 7
        for tools.GetOctectType(rtpBuffer[0]) != 7 {
          rtpBuffer = rtpBuffer[1:]
        }
        // get sps
        sps := make([]byte,len(rtpBuffer[0].Payload))
        copy(sps[:],rtpBuffer[0].Payload[:])
        rtpBuffer = rtpBuffer[1:]
        // get pps
        pps := make([]byte,len(rtpBuffer[0].Payload))
        copy(pps[:],rtpBuffer[0].Payload[:])
        rtpBuffer = rtpBuffer[1:]
        // get sei
        sei := make([]byte, len(rtpBuffer[0].Payload))
        copy(sei[:],rtpBuffer[0].Payload[:])
        rtpBuffer = rtpBuffer[1:]
        // while we haven't reached the next sps in the buffer
        for tools.GetOctectType(rtpBuffer[0]) != 7 {
          switch(tools.GetOctectType(rtpBuffer[0])){
          case 28:
            if tools.GetStartBit(rtpBuffer[0]) == 1{
              var buffer []byte
              buffer = append(buffer, append(itut.StartCode1(),itut.AUD()...)...)
              buffer = append(buffer, append(itut.StartCode1(),sps...)...)
              buffer = append(buffer, append(itut.StartCode1(),pps...)...)
              buffer = append(buffer, append(itut.StartCode1(),sei...)...)
              buffer = append(buffer, itut.StartCode1()...)
              buffer = append(buffer, rtpBuffer[0].Payload[0] & 0xE0 | rtpBuffer[0].Payload[1] & 0x1F )
              buffer = append(buffer, rtpBuffer[0].Payload[2:]...)
              rtpBuffer = rtpBuffer[1:]
              for {
                buffer = append(buffer, rtpBuffer[0].Payload[2:]...)
                if tools.GetEndBit(rtpBuffer[0]) == 1 {
                  rtpBuffer = rtpBuffer[1:]
                  file.Write(buffer)
                  break
                }
                rtpBuffer = rtpBuffer[1:]
              }
            }
          case 1:
            var buffer []byte
            buffer = append(buffer, append(itut.StartCode1(), itut.AUD()...)...)
            buffer = append(buffer, append(itut.StartCode1(), sps...)...)
            buffer = append(buffer, append(itut.StartCode1(),pps...)...)
            buffer = append(buffer, append(itut.StartCode1(),sei...)...)
            buffer = append(buffer, itut.StartCode1()...)
            buffer = append(buffer, rtpBuffer[0].Payload[0] & 0xE0 | rtpBuffer[0].Payload[1] & 0x1F )
            buffer = append(buffer, rtpBuffer[0].Payload[2:]...)
            rtpBuffer = rtpBuffer[1:]
            file.Write(buffer)
          default:
          }
        }
      }
    }
  }
}