use std::path::{Path, PathBuf};
use std::str::FromStr;

use vfile::util::location::Location;

#[derive(Clone, Debug)]
pub enum InputType {
    Location(Location),
    StdIn,
}

#[derive(Clone, Debug)]
pub enum InputFormat {
    Extension(String),
    Auto,
}

#[derive(Clone, Debug)]
pub struct Input {
    pub input: InputType,
    pub format: InputFormat,
}

macro_rules! input_from {
    ($t:ty) => {
        impl From<$t> for Input {
            fn from(loc: $t) -> Self {
                Input {
                    input: InputType::Location(loc.into()),
                    format: InputFormat::Auto,
                }
            }
        }
    };
}

input_from!(&str);
input_from!(&String);
input_from!(String);
input_from!(&Path);
input_from!(&PathBuf);
input_from!(PathBuf);

impl From<Location> for Input {
    fn from(loc: Location) -> Self {
        Input {
            input: InputType::Location(loc),
            format: InputFormat::Auto,
        }
    }
}

impl From<&Location> for Input {
    fn from(loc: &Location) -> Self {
        Input {
            input: InputType::Location(loc.clone()),
            format: InputFormat::Auto,
        }
    }
}

impl FromStr for Input {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Input::from(s))
    }
}

macro_rules! input_format_from {
    ($t:ty) => {
        impl From<$t> for InputFormat {
            fn from(ext: $t) -> Self {
                InputFormat::Extension(ext.to_string())
            }
        }
    };
}

input_format_from!(&str);
input_format_from!(&String);
input_format_from!(String);

impl FromStr for InputFormat {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(InputFormat::from(s))
    }
}
