use libflate::gzip::Decoder;
use std::fs::File;
use std::path::Path;
use std::path::PathBuf;
use std::io::{self, Error, ErrorKind, Read};
use tar::{Archive, EntryType};
use std::io::BufReader;

use packagemeta::PackageMeta;

pub struct Package {
    archive: Archive<Decoder<BufReader<File>>>,
    path: PathBuf,
    meta: Option<PackageMeta>,
}

impl Package {
    pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        let file = File::open(&path)?;
        let decoder = Decoder::new(BufReader::new(file))?;

        let mut ar = Archive::new(decoder);
        ar.set_preserve_permissions(true);
        Ok(Package{archive: ar, path: path.as_ref().to_path_buf(), meta: None})
    }

    pub fn install(&mut self, dest: &str)-> io::Result<()> {
        self.archive.unpack(dest)?;
        Ok(())
    }

    pub fn list(&mut self) -> io::Result<()> {
        for i in self.archive.entries()? {
            println!("{}", i?.path()?.display());
        }
        Ok(())
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn meta(&mut self) -> io::Result<&PackageMeta> {
        if self.meta.is_none() {
            let mut toml = None;
            for entry in self.archive.entries()? {
                let mut entry = entry?;
                if entry.header().entry_type() != EntryType::Directory && entry.path()?.starts_with("pkg") {
                    if toml.is_none() {
                        let mut text = String::new();
                        entry.read_to_string(&mut text)?;
                        toml = Some(text);
                    } else {
                        return Err(Error::new(ErrorKind::Other, "Multiple metadata files in package"));
                    }
                }
            }

            if let Some(toml) = toml {
                self.meta = Some(PackageMeta::from_toml(&toml).map_err(|e| Error::new(ErrorKind::Other, e))?);
            } else {
                return Err(Error::new(ErrorKind::NotFound, "Package metadata not found"));
            }
        }

        Ok(self.meta.as_ref().unwrap())
    }
}
