package leigh.video.edltool;

import leigh.audio.bpm.V4LKBeatDetector;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import leigh.mecha.smpte.Timecode;
import leigh.mecha.util.UniversalJob;
import org.mp4parser.IsoFile;
import org.mp4parser.boxes.iso14496.part12.MovieHeaderBox;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * EDLTool is an application for the creation of EDL/SRT files for machine generative video.
 *
 * @author C. Alexander Leigh
 */
public class EDLTool {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(EDLTool.class);

    public static long getLength(File f) throws IOException {
        IsoFile isoFile = new IsoFile(f);
        MovieHeaderBox mhb = isoFile.getMovieBox().getMovieHeaderBox();
        return mhb.getDuration() / mhb.getTimescale();
    }

    public static void main(String[] args) throws IOException {
        File dir = new File(args[1]);
        File[] directoryListing = dir.listFiles();
        ArrayList<SourceClip> clips = new ArrayList<>();
        File programFile = new File(args[0]);
        int programLength = 4 * 60;

        // Note that this operation is fairly slow, since it actually reads the file
        for (File f : directoryListing) {
            if (!f.isFile() || f.getName().startsWith(".")) continue;
            if (!f.getName().endsWith(".mp4")) continue;

            long length = getLength(f);
            logger.info("Media. [fn: {}] [len: {}]", f.getName(), length);
            // We round to seconds here, good enough.
            clips.add(new SourceClip(f, (int) length));
        }

        if (clips.size() <= 0) {
            logger.error("At least one clip must be provided. ");
            System.exit(UniversalJob.RET_ERROR);
        }

        List<Timecode> beats = V4LKBeatDetector.detect(programFile);
        Timecode last = new Timecode(0);
        int edit = 0;
        Iterator<SourceClip> ic = clips.iterator();

        try (BufferedWriter edl = new BufferedWriter(new FileWriter("/tmp/1.edl"))) {
            try (BufferedWriter srt = new BufferedWriter(new FileWriter("/tmp/1.srt"))) {
                edl.write("TITLE: autogen\nFCM: NON-DROP FRAME\n\n");

                for (Timecode beat : beats) {
                    // Write out SRT
                    srt.write((edit + 1) + "\n");
                    srt.write(last.getCodeWithMillis() + " --> " + beat.getCodeWithMillis() + "\n");
                    srt.write("PLACEHOLDER\n\n");

                    // Write out EDL

                    if (!ic.hasNext()) ic = clips.iterator();
                    SourceClip clip = ic.next();

                    int clipRatio = clip.scale(programLength);
                    int clipSeconds = last.toIntSeconds() * clipRatio;

                    if (clipSeconds > 500) clipSeconds = clipSeconds - 45;

                    logger.info("Calculating. [clipRatio: {}] [clipSeconds: {}] [last: {}] [beat: {}] [last.toIntSec: {}]",
                            clipRatio, clipSeconds, last, beat, last.toIntSeconds());

                    Timecode clipLast = last.clone();
                    Timecode clipBeat = beat.clone();
                    clipLast.addSeconds(clipSeconds);
                    clipBeat.addSeconds(clipSeconds);

                    edl.write(edit + " AX AA/V C " + clipLast.getCode() + " " + clipBeat.getCode() + " " + last.getCode() + " " + beat.getCode() + "\n");

                    edl.write("* FROM CLIP NAME: " + clip.getFile().getName() + "\n");
                    edl.write("* AUDIO LEVEL AT 00:00:00:00 IS -0.00 DB  (REEL AX A1)\n");
                    edl.write("* AUDIO LEVEL AT 00:00:00:00 IS -0.00 DB  (REEL AX A2)\n");
                    edl.write("\n");

                    last = beat;
                    edit++;
                }
            }
        }
    }
}
