1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::{collections::{HashMap, HashSet}, hash::Hash, path::PathBuf};

use crate::structs::*;

//==============================================================================
// List
//==============================================================================
impl ArchiveAuthorsList {
  pub fn from_vector(vec: Vec<ArchiveAuthor>) -> Self {
      let mut vec: Vec<ArchiveAuthorsItem> = vec.into_iter().map(|a| a.into()).collect();
      vec.sort_by(|a, b| a.id.cmp(&b.id));
      ArchiveAuthorsList(vec)
  }
  pub fn extend(&mut self, rhs: Self) {
      let mut authors_map = HashMap::new();

      for author in self.0.iter().cloned() {
          authors_map.insert(author.id.clone(), author);
      }

      for author in rhs.0.iter().cloned() {
          if let Some(old_author) = authors_map.get_mut(&author.id) {
              old_author.extend(author);
          } else {
              authors_map.insert(author.id.clone(), author);
          }
      }

      let mut authors: Vec<ArchiveAuthorsItem> = authors_map.into_values().collect();
      authors.sort_by(|a, b| a.id.cmp(&b.id));
      self.0 = authors;
  }

  pub fn authors(&self) -> Vec<ArchiveAuthorsItem> {
      self.0.clone()
  }
}

impl ArchiveAuthorsItem {
  pub fn extend(&mut self, rhs: Self) {
      self.id = rhs.id;
      self.name = rhs.name;
      self.from = rhs.from;
      self.thumb = rhs.thumb.or(self.thumb.clone());
  }
}

//==============================================================================
// Author
//==============================================================================

impl ArchiveAuthor {
  pub fn extend(&mut self, rhs: Self) {
      let mut posts = HashSet::new();
      posts.extend(self.posts.iter().cloned());
      posts.extend(rhs.posts.iter().cloned());
      let mut posts: Vec<ArchivePostShort> = posts.into_iter().collect();
      posts.sort_by(|a, b| a.updated.cmp(&b.updated));
      posts.reverse();

      self.id = rhs.id;
      self.posts = posts;
      self.name = rhs.name;
      self.from = rhs.from;
      self.thumb = rhs.thumb.or(self.thumb.clone());
  }
}

impl Into<ArchiveAuthorsItem> for ArchiveAuthor {
  fn into(self) -> ArchiveAuthorsItem {
      ArchiveAuthorsItem {
          id: self.id,
          name: self.name,
          thumb: self.thumb,
          from: self.from,
      }
  }
}
//==============================================================================
// Post
//==============================================================================
impl Hash for ArchivePostShort {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state);
        self.from.hash(state);
        self.author.hash(state);
    }
}

impl Into<ArchivePostShort> for ArchivePost {
  fn into(self) -> ArchivePostShort {
    let url = PathBuf::from(&self.author).join(&self.id);
      ArchivePostShort {
          url,
          id: self.id,
          title: self.title,
          author: self.author,
          from: self.from,
          updated: self.updated,
          thumb: self.thumb,
      }
  }
}
//==============================================================================
// Utils
//==============================================================================
impl ArchiveFile {
  pub fn filename(&self) -> &PathBuf {
      match self {
          ArchiveFile::Image { filename, .. } => filename,
          ArchiveFile::Video { filename, .. } => filename,
          ArchiveFile::File { filename, .. } => filename,
      }
  }
  pub fn path(&self) -> &PathBuf {
      match self {
          ArchiveFile::Image { path, .. } => path,
          ArchiveFile::Video { path, .. } => path,
          ArchiveFile::File { path, .. } => path,
      }
  }
  pub fn is_image(&self) -> bool {
      matches!(self, ArchiveFile::Image { .. })
  }
}