// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

extern crate base64;
extern crate image;
#[cfg(feature = "mesalock_sgx")]
extern crate rustface;

use std::convert::TryFrom;
use teaclave_types::{FunctionArguments, FunctionRuntime};

#[derive(Default)]
pub struct FaceDetection;

#[derive(serde::Deserialize)]
struct FaceDetectionArguments {
    image: Vec<u8>,
    /// Set the size of the sliding window.
    ///
    /// The minimum size is constrained as no smaller than 20.
    ///
    /// # Panics
    ///
    /// Panics if `wnd_size` is less than 20.
    window_size: Option<u32>,
    /// Set the sliding window step in horizontal and vertical directions.
    ///
    /// The steps should take positive values.
    /// Usually a step of 4 is a reasonable choice.
    ///
    /// # Panics
    ///
    /// Panics if `step_x` or `step_y` is less than or equal to 0.
    slide_window_step_x: Option<u32>,
    slide_window_step_y: Option<u32>,
    /// Set the minimum size of faces to detect.
    ///
    /// The minimum size is constrained as no smaller than 20.
    ///
    /// # Panics
    ///
    /// Panics if `min_face_size` is less than 20.
    min_face_size: Option<u32>,
    /// Set the maximum size of faces to detect.
    ///
    /// The maximum face size actually used is computed as the minimum among:
    /// user specified size, image width, image height.
    max_face_size: Option<u32>,
    /// Set the factor between adjacent scales of image pyramid.
    ///
    /// The value of the factor lies in (0.1, 0.99). For example, when it is set as 0.5,
    /// an input image of size w x h will be resized to 0.5w x 0.5h, 0.25w x 0.25h,  0.125w x 0.125h, etc.
    ///
    /// # Panics
    ///
    /// Panics if `scale_factor` is less than 0.01 or greater than 0.99
    pyramid_scale_factor: Option<f32>,
    /// Set the score threshold of detected faces.
    ///
    /// Detections with scores smaller than the threshold will not be returned.
    /// Typical threshold values include 0.95, 2.8, 4.5. One can adjust the
    /// threshold based on his or her own test set.
    ///
    /// Smaller values result in more detections (possibly increasing the number of false positives),
    /// larger values result in fewer detections (possibly increasing the number of false negatives).
    ///
    /// # Panics
    ///
    /// Panics if `thresh` is less than or equal to 0.
    score_thresh: Option<f64>,
}

impl TryFrom<FunctionArguments> for FaceDetectionArguments {
    type Error = anyhow::Error;

    fn try_from(arguments: FunctionArguments) -> Result<Self, Self::Error> {
        use anyhow::Context;
        serde_json::from_str(&arguments.into_string()).context("Cannot deserialize arguments")
    }
}

impl FaceDetection {
    pub const NAME: &'static str = "builtin-face-detection";

    pub fn new() -> Self {
        Default::default()
    }

    pub fn run(
        &self,
        arguments: FunctionArguments,
        _runtime: FunctionRuntime,
    ) -> anyhow::Result<String> {
        let arguments = FaceDetectionArguments::try_from(arguments)?;
        let image = arguments.image;
        let img = image::load_from_memory(&image)?;

        let mut detector = rustface::create_default_detector()?;
        if let Some(window_size) = arguments.window_size {
            detector.set_window_size(window_size);
        }
        if let (Some(step_x), Some(step_y)) =
            (arguments.slide_window_step_x, arguments.slide_window_step_y)
        {
            detector.set_slide_window_step(step_x, step_y);
        }
        if let Some(min_face_size) = arguments.min_face_size {
            detector.set_min_face_size(min_face_size);
        }
        if let Some(max_face_size) = arguments.max_face_size {
            detector.set_max_face_size(max_face_size);
        }
        if let Some(pyramid_scale_factor) = arguments.pyramid_scale_factor {
            detector.set_pyramid_scale_factor(pyramid_scale_factor);
        }
        if let Some(score_thresh) = arguments.score_thresh {
            detector.set_score_thresh(score_thresh);
        }

        let faces = rustface::detect_faces(&mut *detector, img);
        let result = serde_json::to_string(&faces)?;

        Ok(result)
    }
}

#[cfg(feature = "enclave_unit_test")]
pub mod tests {
    use super::*;
    use serde_json::json;
    use std::untrusted::fs;
    use teaclave_runtime::*;
    use teaclave_test_utils::*;
    use teaclave_types::*;

    pub fn run_tests() -> bool {
        run_tests!(test_face_detection)
    }

    fn test_face_detection() {
        let input = "fixtures/functions/face_detection/input.jpg";
        let image = fs::read(input).unwrap();
        let arguments = FunctionArguments::from_json(json!({
            "image": &image,
            "min_face_size": 20,
            "score_thresh": 2.0,
            "pyramid_scale_factor": 0.8,
            "slide_window_step_x": 4,
            "slide_window_step_y": 4
        }))
        .unwrap();

        let input_files = StagedFiles::new(hashmap!());
        let output_files = StagedFiles::new(hashmap!());
        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));

        let result = FaceDetection::new().run(arguments, runtime).unwrap();
        let json_result: serde_json::Value = serde_json::from_str(&result).unwrap();
        assert_eq!(json_result.as_array().unwrap().len(), 29);
    }
}
