use serde::Serialize;
use std::io;

mod sha256;
pub use sha256::Sha256;

mod date;
pub use date::Date;

mod texture_format;
pub use texture_format::TextureFormat;

#[derive(Eq, PartialEq, PartialOrd, Ord, Clone, Serialize, Deserialize, Debug, Hash)]
pub struct Texture {
    // Mainly sort by: (Ord is derived.)
    pub name: String,
    pub added_on: Date,
    // other attributes
    pub id: String,
    pub tags: Vec<String>,
    pub resolution: (u64, u64),
    //
    pub format: TextureFormat,
    pub texture_hash: Sha256,
}

pub enum ReplaceTextureStatus {
    /// Done.
    Ok,

    /// Call Again With Texture Binary
    NeedTextureData(Sha256),
}

pub type ProtocolResult<T> = Result<T, ProtocolError>;
pub enum ProtocolError {
    BadRequest(String),
    FileNotFound(String),
    Conflict(String),
    InternalServerError(std::io::Error),
    NotImplemented,
}

impl From<io::Error> for ProtocolError {
    fn from(err: io::Error) -> Self {
        if err.kind() == io::ErrorKind::NotFound {
            ProtocolError::FileNotFound("File Not Found!".to_string())
        } else {
            ProtocolError::InternalServerError(err)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::str::FromStr;

    /// just a shorthand
    fn tex(id: i32, name: &str, tags: &str, added_on: &str, resolution: u64) -> Texture {
        Texture {
            id: format!("{}", id), // Id should actaly be a uuid, but for testing this is fine.
            name: name.to_string(),
            tags: tags.split(",").map(|s| s.trim().to_string()).collect(),
            added_on: Date::from_str(added_on).unwrap(),
            resolution: (resolution, resolution),
            format: TextureFormat::JPEG,
            texture_hash: Sha256::from_data(b"Some Hash"),
        }
    }

    #[test]
    fn textures_are_sorted_by_name() {
        let tex1 = tex(1, "AAAAA", "Z", "2019-05-15", 2);
        let tex2 = tex(0, "B", "A", "2000-01-11", 1);

        assert!(tex1 < tex2);
    }
}
