#! /usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright 2016 Google Inc. All rights reserved.
#
# 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.

"""MPEG4 processing classes.

Functions for loading MP4/MOV files and manipulating boxes.
"""

from spatialmedia.mpeg import box
from spatialmedia.mpeg import constants
from spatialmedia.mpeg import container


def load(fh):
    """Load the mpeg4 file structure of a file.

    Args:
      fh: file handle, input file handle.
      position: int, current file position.
      size: int, maximum size. This is used to ensure correct box sizes.

    return:
      mpeg4, the loaded mpeg4 structure.
    """

    fh.seek(0, 2)
    size = fh.tell()
    contents = container.load_multiple(fh, 0, size)

    if not contents:
        print("Error, failed to load .mp4 file.")
        return None
    elif len(contents) == 0:
        print("Error, no boxes found.")
        return None

    loaded_mpeg4 = Mpeg4Container()
    loaded_mpeg4.contents = contents

    for element in loaded_mpeg4.contents:
        if (element.name == constants.TAG_MOOV):
            loaded_mpeg4.moov_box = element
        if (element.name == constants.TAG_FREE):
            loaded_mpeg4.free_box = element
        if (element.name == constants.TAG_MDAT
                and not loaded_mpeg4.first_mdat_box):
            loaded_mpeg4.first_mdat_box = element
        if (element.name == constants.TAG_FTYP):
            loaded_mpeg4.ftyp_box = element

    if not loaded_mpeg4.moov_box:
        print("Error, file does not contain moov box.")
        return None

    if not loaded_mpeg4.first_mdat_box:
        print("Error, file does not contain mdat box.")
        return None

    loaded_mpeg4.first_mdat_position = \
        loaded_mpeg4.first_mdat_box.position
    loaded_mpeg4.first_mdat_position += \
        loaded_mpeg4.first_mdat_box.header_size

    loaded_mpeg4.content_size = 0
    for element in loaded_mpeg4.contents:
        loaded_mpeg4.content_size += element.size()

    return loaded_mpeg4


class Mpeg4Container(container.Container):
    """Specialized behaviour for the root mpeg4 container."""

    def __init__(self):
        self.contents = list()
        self.content_size = 0
        self.header_size = 0
        self.moov_box = None
        self.free_box = None
        self.first_mdat_box = None
        self.ftyp_box = None
        self.first_mdat_position = None
        self.padding = 0

    def merge(self, element):
        """Mpeg4 containers do not support merging."""
        print("Cannot merge mpeg4 files")
        exit(0)

    def print_structure(self):
        """Print mpeg4 file structure recursively."""
        print("mpeg4 [{}]".format(self.content_size))

        size = len(self.contents)
        for i in range(size):
            next_indent = " ├──"
            if i == (size - 1):
                next_indent = " └──"

            self.contents[i].print_structure(next_indent)

    def save(self, in_fh, out_fh):
        """Save mpeg4 filecontent to file.

        Args:
          in_fh: file handle, source file handle for uncached contents.
          out_fh: file handle, destination file hand for saved file.
        """
        self.resize()
        new_position = 0
        for element in self.contents:
            if element.name == constants.TAG_MDAT:
                new_position += element.header_size
                break
            new_position += element.size()
        delta = new_position - self.first_mdat_position

        for element in self.contents:
            element.save(in_fh, out_fh, delta)
