#![allow(clippy::unit_arg)]

use maraiah::{durandal::{err::*, file::*, image::*, sound::*},
              marathon::{machdr, map, ppm, shp, snd, tga, wav}};
use std::{fs, io, slice::from_ref};

fn open(path: &str) -> ResultS<memmap::Mmap>
{
   let fp = fs::File::open(path)?;
   Ok(unsafe {memmap::Mmap::map(&fp)?})
}

fn file_read<T, F>(path: &str, f: F) -> ResultS<T>
   where F: FnOnce(&[u8]) -> ResultS<T>
{
   let mm = open(path)?;
   let bp = &mm[machdr::try_mac_header(&mm)..];

   f(bp)
}

fn exists(path: String) -> Result<(), String>
{
   match std::fs::metadata(path) {
      Ok(_)  => Ok(()),
      Err(e) => Err(e.to_string()),
   }
}

fn each_value<'a, F>(opt: &'a clap::ArgMatches<'a>, name: &str, mut f: F)
   -> ResultS<()>
   where F: FnMut(&'a str) -> ResultS<()>
{
   if let Some(values) = opt.values_of(name) {
      for value in values {
         f(value)?;
      }
   }

   Ok(())
}

fn dump_info(data: impl std::fmt::Debug)
{
   println!("{:#?}", data);
}

fn sub_data_c<'a>(_opt: &clap::ArgMatches<'a>) -> ResultS<()>
{
   unimplemented!();
}

fn sub_dump_c<'a>(_opt: &clap::ArgMatches<'a>) -> ResultS<()>
{
   unimplemented!();
}

fn sub_info_c<'a>(opt: &clap::ArgMatches<'a>) -> ResultS<()>
{
   each_value(opt, "map", |f| Ok(dump_info(file_read(f, map::read)?)))?;
   each_value(opt, "shp", |f| Ok(dump_info(file_read(f, shp::read)?)))?;
   each_value(opt, "snd", |f| Ok(dump_info(file_read(f, snd::read)?)))?;

   Ok(())
}

fn main() -> ResultS<()>
{
   use clap::clap_app;

   let sub_data =
      clap_app!(@subcommand data =>
         (about: "Dumps data into a discrete folder/YAML format"));

   let sub_dump =
      clap_app!(@subcommand dump =>
         (about: "Dumps particular parts of data"));

   let sub_info =
      clap_app!(@subcommand info =>
         (about: "Outputs debug info")
         (@group files =>
            (@attributes +required +multiple)
            (@arg map: -m --map [file]... {exists} "Loads a Map file")
            (@arg shp: -s --shp [file]... {exists} "Loads a Shapes file")
            (@arg snd: -n --snd [file]... {exists} "Loads a Sounds file")));

   let opt =
      clap_app!((env!("CARGO_PKG_NAME")) =>
         (version:    env!("CARGO_PKG_VERSION"))
         (author:     env!("CARGO_PKG_AUTHORS"))
         (about:      env!("CARGO_PKG_DESCRIPTION"))
         (setting:    clap::AppSettings::SubcommandRequiredElseHelp)
         (subcommand: sub_data)
         (subcommand: sub_dump)
         (subcommand: sub_info));

   let opt = opt.get_matches();

   match opt.subcommand() {
      ("data", Some(opt)) => sub_data_c(opt)?,
      ("dump", Some(opt)) => sub_dump_c(opt)?,
      ("info", Some(opt)) => sub_info_c(opt)?,
      _ => unreachable!(),
   }

   Ok(())
}

// EOF
