package org.forkalsrud.album.video;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MovieMetadataGenerator {

    private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MovieMetadataGenerator.class);

    private String exiftoolExecutable;


    public MovieMetadataGenerator() throws IOException, InterruptedException {
        ExecUtil util = new ExecUtil();
        this.exiftoolExecutable = util.findExecutableInShellPath("exiftool");
    }






    /**
     *
     * @param f the movie file
     * @return a map with the following keys: orientation dimensions captureDate comment etag
     * @throws IOException
     * @throws InterruptedException
     */
    public Map<String, String> generateVideoProperties(File f) throws IOException, InterruptedException {

    	/*
    	 * [{
  "SourceFile": "/home/erik/local/IMG_0837.mov",
  "ExifToolVersion": 9.12,
  "FileName": "IMG_0837.mov",
  "Directory": "/home/erik/local",
  "FileSize": "1438 kB",
  "FileModifyDate": "2013:01:19 18:36:53-08:00",
  "FileAccessDate": "2013:01:19 18:36:57-08:00",
  "FileInodeChangeDate": "2013:01:19 18:36:53-08:00",
  "FilePermissions": "rw-rw-r--",
  "FileType": "MOV",
  "MIMEType": "video/quicktime",
  "MajorBrand": "Apple QuickTime (.MOV/QT)",
  "MinorVersion": "0.0.0",
  "CompatibleBrands": ["qt  "],
  "MovieDataSize": 1467141,
  "MovieHeaderVersion": 0,
  "ModifyDate": "2012:12:30 06:44:31",
  "TimeScale": 600,
  "Duration": "9.07 s",
  "PreferredRate": 1,
  "PreferredVolume": "100.00%",
  "PreviewTime": "0 s",
  "PreviewDuration": "0 s",
  "PosterTime": "0 s",
  "SelectionTime": "0 s",
  "SelectionDuration": "0 s",
  "CurrentTime": "0 s",
  "NextTrackID": 3,
  "TrackHeaderVersion": 0,
  "TrackCreateDate": "2012:12:30 06:44:26",
  "TrackModifyDate": "2012:12:30 06:44:31",
  "TrackID": 1,
  "TrackDuration": "9.05 s",
  "TrackLayer": 0,
  "TrackVolume": "100.00%",
  "Balance": 0,
  "AudioChannels": 1,
  "AudioBitsPerSample": 16,
  "AudioSampleRate": 44100,
  "AudioFormat": "chan",
  "MatrixStructure": "0 1 0 -1 0 0 540 0 1",
  "ImageWidth": 960,
  "ImageHeight": 540,
  "CleanApertureDimensions": "960x540",
  "ProductionApertureDimensions": "960x540",
  "EncodedPixelsDimensions": "960x540",
  "MediaHeaderVersion": 0,
  "MediaCreateDate": "2012:12:30 06:44:26",
  "MediaModifyDate": "2012:12:30 06:44:31",
  "MediaTimeScale": 600,
  "MediaDuration": "9.10 s",
  "MediaLanguageCode": "und",
  "GraphicsMode": "ditherCopy",
  "OpColor": "32768 32768 32768",
  "HandlerClass": "Data Handler",
  "HandlerVendorID": "Apple",
  "HandlerDescription": "Core Media Data Handler",
  "CompressorID": "avc1",
  "SourceImageWidth": 960,
  "SourceImageHeight": 540,
  "XResolution": 72,
  "YResolution": 72,
  "CompressorName": "H.264",
  "BitDepth": 24,
  "VideoFrameRate": 30,
  "CameraIdentifier": "Back",
  "FrameReadoutTime": "28512 microseconds",
  "Make": "Apple",
  "SoftwareVersion": "6.0.1",
  "CreateDate": "2012:12:29 16:30:21-08:00",
  "Model": "iPhone 4S",
  "HandlerType": "Metadata Tags",
  "Make-und-US": "Apple",
  "CreationDate-und-US": "2012:12:29 16:30:21-08:00",
  "Software-und-US": "6.0.1",
  "Model-und-US": "iPhone 4S",
  "AvgBitrate": "1.29 Mbps",
  "ImageSize": "960x540",
  "Rotation": 90
}]
    	 */
        Map<String, String> props = new HashMap<String, String>();
        ProcessBuilder pb = new ProcessBuilder().command(
                this.exiftoolExecutable, "-j", "-n", f.getAbsolutePath());
        pb.redirectErrorStream(false);
        Process p = pb.start();
        p.getOutputStream().close();

        ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
        @SuppressWarnings("unchecked")
        List<Map<String,Object>> userDataList = mapper.readValue(p.getInputStream(), List.class);
        p.waitFor();

        props.put("type", "movie");

        Map<String, Object> userData = userDataList.get(0);

        // System.out.println(userData);
        {
            // The orientation is about flipping and rotating.  Here is what an 'F' looks like
            // on pictures with each orientation.
            //
            //   1        2       3      4         5            6           7          8
            //
            // 888888  888888      88  88      8888888888  88                  88  8888888888
            // 88          88      88  88      88  88      88  88          88  88      88  88
            // 8888      8888    8888  8888    88          8888888888  8888888888          88
            // 88          88      88  88
            // 88          88  888888  888888
            //
            // The first four are obtained with only flipping X and/or Y
            // The last four are obtained by rotating 90 degrees and then flipping X and/or Y.
            //
            String orientation;
            Object rotationObj = userData.get("Rotation");
            if (rotationObj == null) {
                orientation = "1";
            } else {
                String rotation = rotationObj.toString();
                if ("0".equals(rotation)) {
                    orientation = "1";
                } else if ("90".equals(rotation)) {
                    orientation = "6";
                } else if ("180".equals(rotation)) {
                    orientation = "3";
                } else if ("270".equals(rotation)) {
                    orientation = "8";
                } else {
                    log.warn("unknown rotation: " + rotation + " for file " + f);
                    orientation = "1";
                }
            }
            props.put("orientation", orientation);
        }

        Object imageSize = userData.get("ImageSize");
        if (imageSize == null) {
            imageSize = props.get("ImageWidth") + "x" + props.get("ImageHeight");
        }
        props.put("dimensions", imageSize.toString());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
        props.put("captureDate", sdf.format(new Date(f.lastModified())));

        props.put("etag", Integer.toHexString(f.getName().hashCode() + Long.valueOf(f.lastModified()).hashCode()));
        for (String prop : new String[] { "Duration", "MediaDuration", "PlayDuration" }) {
            Object o = userData.get(prop);
            if (o != null) {
                props.put("length", o.toString().split(" ")[0]);
                break;
            }
        }
        return props;
    }

}
