/**********************************************************************************
* Blueprint Reality Inc. CONFIDENTIAL
* 2020 Blueprint Reality Inc.
* All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains, the property of
* Blueprint Reality Inc. and its suppliers, if any.  The intellectual and
* technical concepts contained herein are proprietary to Blueprint Reality Inc.
* and its suppliers and may be covered by Patents, pending patents, and are
* protected by trade secret or copyright law.
*
* Dissemination of this information or reproduction of this material is strictly
* forbidden unless prior written permission is obtained from Blueprint Reality Inc.
***********************************************************************************/

using BlueprintReality.Interprocess;
using BlueprintReality.Interprocess.Textures;
using BlueprintReality.MixCast.Data;
using BlueprintReality.MixCast.Shared;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace BlueprintReality.MixCast
{
    public class ExpFrameSender : IDisposable
    {
        public ExpCameraBehaviour cam;

        public int chainSize = 3;

        private SharedSurfaceProducer writer;

        bool firstWriteCompleted = false;
        bool recordingMissedLastFrame;


        public ExpFrameSender(ExpCameraBehaviour cam)
        {
            this.cam = cam;
            ExpCameraBehaviour.FrameEnded += HandleFrameUpdated;
        }
        public void Dispose()
        {
            if (writer != null)
            {
                writer.PushEndOfFile(1000);
                writer.Dispose();
                writer = null;
            }
            ExpCameraBehaviour.FrameEnded -= HandleFrameUpdated;
        }

        private ulong lastPushedIdealTime;

        private void HandleFrameUpdated(ExpCameraBehaviour curCam)
        {
            if (ExpCameraBehaviour.CurrentlyRendering != cam)
                return;

            VirtualCamera camInfo = MixCastSdkData.GetCameraWithId(cam.cameraContext.Identifier);

            //lazy init
            if (writer == null)
            {
                writer = new SharedSurfaceProducer(SharedTexIds.Cameras.ExperienceLayers.Get(cam.cameraContext.Identifier), chainSize);
            }

            if (cam.Timer.LastIdealTime == lastPushedIdealTime)
                Debug.Log("Got same ideal time twice in a row! for both " + cam.Timer.LastIdealTime + " and " + lastPushedIdealTime);
            else
            {
                ulong oldMidnightIndex = FrameTimer.GetMidnightRelativeFrameIndex(lastPushedIdealTime, camInfo.RenderFramerate);
                ulong newMidnightIndex = FrameTimer.GetMidnightRelativeFrameIndex(cam.Timer.LastIdealTime, camInfo.RenderFramerate);
                if (cam.notifyWhenFrameDropped && oldMidnightIndex == newMidnightIndex)
                    UnityEngine.Debug.LogError(string.Format("ExpFrameSender: Duplicate 'from-midnight' index detected from both {0} and {1}!", lastPushedIdealTime, cam.Timer.LastIdealTime));
            }
            lastPushedIdealTime = cam.Timer.LastIdealTime;

            if (!writer.TryPushFrame(cam.LayersTexture, cam.Timer.LastIdealTime, cam.Timer.LastUpdateTime, cam.Timer.LastFrameIndex, 0))
            {
                if (!recordingMissedLastFrame && firstWriteCompleted && cam.notifyWhenFrameDropped)
                {
                    //VirtualCamera camInfo = MixCastSdkData.GetCameraWithId(cam.cameraContext.Identifier);
                    Debug.LogWarning(string.Format("Compositing process started missing frames at time {0}",
                        MixCastTimestamp.GetSMPTE(FrameTimer.GetMidnightRelativeFrameIndex(cam.Timer.LastIdealTime, camInfo.RenderFramerate), camInfo.RenderFramerate)));
                }
                recordingMissedLastFrame = true;
                return;
            }

            if (!firstWriteCompleted)
            {
                firstWriteCompleted = true;
                recordingMissedLastFrame = false;

                if (cam.notifyWhenFrameDropped)
                {
                    //VirtualCamera camInfo = MixCastSdkData.GetCameraWithId(cam.cameraContext.Identifier);
                    Debug.Log(string.Format("Compositing process started at time {0}",
                        MixCastTimestamp.GetSMPTE(FrameTimer.GetMidnightRelativeFrameIndex(cam.Timer.LastIdealTime, camInfo.RenderFramerate), camInfo.RenderFramerate)));
                }
            }

            if (recordingMissedLastFrame && cam.notifyWhenFrameDropped)
            {
                //VirtualCamera camInfo = MixCastSdkData.GetCameraWithId(cam.cameraContext.Identifier);
                Debug.Log(string.Format("Compositing process back in business at time {0}",
                    MixCastTimestamp.GetSMPTE(FrameTimer.GetMidnightRelativeFrameIndex(cam.Timer.LastIdealTime, camInfo.RenderFramerate), camInfo.RenderFramerate)));
            }

            recordingMissedLastFrame = false;
        }
    }
}
