use std::borrow::{ToOwned};
use std::error::{Error};
use std::fs::{File};
use std::io::{Read};
use std::mem;
use std::path::{Path};
use bencode::{Bencode, BencodeView, DecodeBencode};
use torrent::{Torrent, ContactType, InfoHash};
use torrent::error::{TorrentError, TorrentResult};
use torrent::parse::{self};
use util::{self};
enum Contact<'a> {
Tracker(&'a str),
Trackerless(Vec<(&'a str, u16)>),
Either(&'a str, Vec<(&'a str, u16)>),
None
}
pub struct MetainfoView<'a> {
contact: Contact<'a>,
comment: Option<&'a str>,
created_by: Option<&'a str>,
creation_date: Option<i64>,
info: InfoView<'a>,
info_hash: InfoHash
}
impl<'a> MetainfoView<'a> {
pub fn new<T>(bencode: &'a T) -> TorrentResult<MetainfoView<'a>>
where T: BencodeView<InnerItem=T> {
let info = try!(InfoView::new(bencode));
let info_hash = try!(parse::generate_info_hash(bencode));
let announce = parse::slice_announce(bencode);
let nodes = parse::slice_nodes(bencode);
let contact = match (announce, nodes) {
(Ok(a), Ok(n)) => Contact::Either(a, n),
(Ok(a), Err(_)) => Contact::Tracker(a),
(Err(_), Ok(n)) => Contact::Trackerless(n),
(Err(_), Err(_)) => Contact::None
};
let comment = try!(parse::slice_comment(bencode));
let created_by = try!(parse::slice_created_by(bencode));
let creation_date = try!(parse::slice_creation_date(bencode));
Ok(MetainfoView{
contact: contact,
comment: comment,
created_by: created_by,
creation_date: creation_date,
info: info,
info_hash: info_hash
})
}
}
impl<'b> Torrent for MetainfoView<'b> {
fn contact_type<'a>(&'a self) -> ContactType<'a> {
match self.contact {
Contact::Tracker(a) => ContactType::Tracker(a),
Contact::Trackerless(ref b) => ContactType::Trackerless(&b[..]),
Contact::Either(a, ref b) => ContactType::Either(a, &b[..]),
Contact::None => ContactType::None
}
}
fn comment(&self) -> Option<&str> {
self.comment
}
fn created_by(&self) -> Option<&str> {
self.created_by
}
fn creation_date(&self) -> Option<i64> {
self.creation_date
}
fn info<'a>(&'a self) -> &InfoView<'a> {
&self.info
}
fn info_hash(&self) -> &InfoHash {
&self.info_hash
}
}
pub struct InfoView<'a> {
files: Vec<FileView<'a>>,
pieces: &'a [u8],
piece_length: i64
}
impl<'a> InfoView<'a> {
fn new<T>(root: &'a T) -> TorrentResult<InfoView<'a>>
where T: BencodeView<InnerItem=T> {
let files = try!(parse::slice_files(root));
let file_views = files.into_iter().map(|(len, sum, path)|
FileView{ length: len, path: path, checksum: sum }
).collect();
Ok(InfoView{ files: file_views,
pieces: try!(parse::slice_pieces(root)),
piece_length: try!(parse::slice_piece_length(root))
})
}
pub fn num_pieces(&self) -> usize {
self.pieces.len()
}
pub fn piece_hash(&self, index: usize) -> Option<&[u8]> {
let start_index = index * util::SHA1_HASH_LEN;
let end_index = start_index + util::SHA1_HASH_LEN;
if end_index >= self.pieces.len() {
None
} else {
Some(&self.pieces[start_index..end_index])
}
}
pub fn piece_length(&self) -> i64 {
self.piece_length
}
pub fn files(&self) -> &[FileView<'a>] {
&self.files[..]
}
}
pub struct FileView<'a> {
length: i64,
path: Vec<&'a str>,
checksum: Option<&'a [u8]>
}
impl<'a> FileView<'a> {
pub fn file_size(&self) -> i64 {
self.length
}
pub fn checksum(&self) -> Option<&[u8]> {
self.checksum
}
pub fn path(&self) -> &[&str] {
&self.path[..]
}
}