From 3ad8b78e9dc760ca11eb0001a0347272ceb13c12 Mon Sep 17 00:00:00 2001
From: MrDulfin <Dulfinaminator@gmail.com>
Date: Sun, 11 Feb 2024 15:54:11 -0500
Subject: [PATCH] started work on controller protoype

---
 src/music_controller/controller.rs           | 206 ++++++++++++++++++-
 src/music_storage/db_reader/itunes/reader.rs |  21 +-
 src/music_storage/playlist.rs                |  12 +-
 3 files changed, 226 insertions(+), 13 deletions(-)

diff --git a/src/music_controller/controller.rs b/src/music_controller/controller.rs
index 7f62871..98c3ca8 100644
--- a/src/music_controller/controller.rs
+++ b/src/music_controller/controller.rs
@@ -2,25 +2,219 @@
 //! player. It manages queues, playback, library access, and
 //! other functions
 
+use std::path::PathBuf;
 use std::sync::{Arc, RwLock};
+use std::time::Duration;
+use crossbeam_channel::{Sender, Receiver};
+// use std::sync::mpsc;
+use crossbeam_channel;
+use gstreamer::format::Default;
+use gstreamer::query::Uri;
+use std::thread::{self, sleep, spawn};
 
+use std::error::Error;
+use crossbeam_channel::unbounded;
+use rayon::iter::Rev;
+use uuid::Uuid;
+
+use crate::config;
+use crate::music_storage::library::Tag;
+use crate::music_storage::playlist::Playlist;
 use crate::{
     music_player::Player,
-    music_storage::library::Song,
-    config::config::Config
+    music_storage::{
+        library::{MusicLibrary, Song}
+    },
+    config::config::Config,
 };
 
 struct Queue {
     player: Player,
     name: String,
-    songs: Vec<Song>,
+    songs: Playlist,
+}
+impl Queue {
+    fn new() -> Result<Self, Box<dyn Error>> {
+        Ok(
+            Queue {
+            player: Player::new()?,
+            name: String::new(),
+            songs: Playlist::new()
+            }
+        )
+    }
 }
 
 pub struct Controller {
-    queues: Vec<Queue>,
+    // queues: Vec<Queue>,
     config: Arc<RwLock<Config>>,
+    // library: MusicLibrary,
+    controller_mail: MailMan<ControllerCommand, ControllerResponse>,
+    db_mail: MailMan<DatabaseCommand, DatabaseResponse>,
+    queue_mail: Vec<MailMan<QueueCommand, QueueResponse>>,
+}
+#[derive(Debug)]
+
+pub enum ControllerCommand {
+    Default,
+    Test
+}
+#[derive(Debug)]
+
+enum ControllerResponse {
+    Empty,
+    QueueMailMan(MailMan<QueueCommand, QueueResponse>),
+
+}
+#[derive(Debug)]
+
+pub enum DatabaseCommand {
+    Default,
+    Test,
+    GetSongs,
+
+}
+#[derive(Debug)]
+
+enum DatabaseResponse {
+    Empty,
+    Songs(Vec<Song>),
+}
+#[derive(Debug)]
+enum QueueCommand {
+    Default,
+    Test,
+    Play,
+    Pause,
+}
+#[derive(Debug)]
+enum QueueResponse {
+    Default,
+    Test,
 }
 
-impl Controller {
-    // more stuff to come
+#[derive(Debug)]
+
+struct MailMan<T, U> {
+    pub tx: Sender<T>,
+    rx: Receiver<U>
 }
+impl<T> MailMan<T, T> {
+    pub fn new() -> Self {
+        let (tx, rx) = unbounded::<T>();
+        MailMan { tx, rx }
+    }
+}
+impl<T, U> MailMan<T, U> {
+    pub fn double() -> (MailMan<T, U>, MailMan<U, T>) {
+        let (tx, rx) = unbounded::<T>();
+        let (tx1, rx1) = unbounded::<U>();
+
+        (
+            MailMan { tx, rx: rx1 },
+            MailMan { tx: tx1, rx }
+        )
+    }
+
+    pub fn send(&self, mail: T) -> Result<(), Box<dyn Error>> {
+        &self.tx.send(mail).unwrap();
+        Ok(())
+    }
+
+    pub fn recv(&self) -> Result<U, Box<dyn Error>> {
+        let u = self.rx.recv().unwrap();
+        Ok(u)
+    }
+}
+
+#[allow(unused_variables)]
+impl Controller {
+    pub fn start(config: PathBuf) -> Result<Self, Box<dyn Error>> {
+        let config = Config::read_file(config)?;
+        let uuid = config.libraries.get_default()?.uuid;
+
+        let config = Arc::new(RwLock::from(config));
+        let lib = MusicLibrary::init(config.clone(), uuid)?;
+
+        let (out_thread_controller, in_thread) = MailMan::double();
+        let monitor_thread = spawn(move || {
+            use ControllerCommand::*;
+            loop {
+                let command = in_thread.recv().unwrap();
+
+                match command {
+                    Default => (),
+                    Test => {
+                        in_thread.send(ControllerResponse::Empty).unwrap();
+                    },
+                }
+            }
+        });
+
+
+        let (out_thread_db, in_thread) = MailMan::double();
+        let db_monitor = spawn(move || {
+            use DatabaseCommand::*;
+            loop {
+                let command = in_thread.recv().unwrap();
+
+                match command {
+                    Default => {},
+                    Test => {
+                        in_thread.send(DatabaseResponse::Empty).unwrap();
+                    },
+                    GetSongs => {
+                        let songs = lib.query_tracks(&String::from(""), &(vec![Tag::Title]), &(vec![Tag::Title])).unwrap().iter().cloned().cloned().collect();
+                        in_thread.send(DatabaseResponse::Songs(songs)).unwrap();
+                    },
+
+                }
+            }
+        });
+
+
+
+        Ok(
+            Controller {
+                // queues: Vec::new(),
+                config,
+                controller_mail: out_thread_controller,
+                db_mail: out_thread_db,
+                queue_mail: Vec::new(),
+            }
+        )
+    }
+    fn get_db_songs(&self) -> Vec<Song> {
+        self.db_mail.send(DatabaseCommand::GetSongs);
+        match self.db_mail.recv().unwrap() {
+            DatabaseResponse::Songs(songs) => songs,
+            _ => Vec::new()
+        }
+
+    }
+    pub fn new_queue(&mut self) {
+        let (out_thread_queue, in_thread) = MailMan::<QueueCommand, QueueResponse>::double();
+        let queues_monitor =  spawn(move || {
+            use QueueCommand::*;
+            loop {
+                let command = in_thread.recv().unwrap();
+                match command {
+                    Default => {},
+                    Test => {},
+                    Play => {},
+                    Pause => {},
+                }
+            }
+        });
+        self.queue_mail.push(out_thread_queue);
+    }
+}
+
+#[test]
+fn name() {
+    let a = Controller::start(PathBuf::from("test-config/config_test.json")).unwrap();
+    // sleep(Duration::from_millis(5000));
+    _ = a.controller_mail.send(ControllerCommand::Test);
+    // dbg!(a.get_db_songs());
+    // sleep(Duration::from_secs(6));
+}
\ No newline at end of file
diff --git a/src/music_storage/db_reader/itunes/reader.rs b/src/music_storage/db_reader/itunes/reader.rs
index c2063c0..3bc73f6 100644
--- a/src/music_storage/db_reader/itunes/reader.rs
+++ b/src/music_storage/db_reader/itunes/reader.rs
@@ -2,17 +2,20 @@ use file_format::FileFormat;
 use lofty::{AudioFile, LoftyError, ParseOptions, Probe, TagType, TaggedFileExt};
 use quick_xml::events::Event;
 use quick_xml::reader::Reader;
+use uuid::Uuid;
 use std::collections::{BTreeMap, HashMap};
 use std::fs::File;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
+use std::sync::{Arc, RwLock};
 use std::time::Duration as StdDur;
 use std::vec::Vec;
 
 use chrono::prelude::*;
 
+use crate::config::config::{Config, ConfigLibrary};
 use crate::music_storage::db_reader::extern_library::ExternalLibrary;
-use crate::music_storage::library::{AlbumArt, Service, Song, Tag, URI};
+use crate::music_storage::library::{AlbumArt, MusicLibrary, Service, Song, Tag, URI};
 use crate::music_storage::utils;
 
 use urlencoding::decode;
@@ -320,4 +323,20 @@ impl ITunesSong {
         // println!("{:.2?}", song);
         Ok(song)
     }
+}
+
+#[test]
+fn itunes_lib_test() {
+    let mut config = Config::read_file(PathBuf::from("test-config/config_test.json")).unwrap();
+    let config_lib = ConfigLibrary::new(PathBuf::from("test-config/library2"), String::from("library2"), None);
+    config.libraries.libraries.push(config_lib.clone());
+
+    let songs = ITunesLibrary::from_file(Path::new("test-config\\iTunesLib.xml")).to_songs();
+
+    let mut library = MusicLibrary::init(Arc::new(RwLock::from(config.clone())), config_lib.uuid).unwrap();
+
+    songs.iter().for_each(|song| library.add_song(song.to_owned()).unwrap());
+
+    config.write_file().unwrap();
+    library.save(config).unwrap();
 }
\ No newline at end of file
diff --git a/src/music_storage/playlist.rs b/src/music_storage/playlist.rs
index c2c6b74..69ae390 100644
--- a/src/music_storage/playlist.rs
+++ b/src/music_storage/playlist.rs
@@ -23,15 +23,15 @@ pub enum SortOrder {
     Tag(Tag)
 }
 #[derive(Debug, Clone)]
-pub struct Playlist<'a> {
+pub struct Playlist {
     title: String,
-    cover: Option<&'a AlbumArt>,
+    cover: Option<AlbumArt>,
     tracks: Vec<Uuid>,
     sort_order: SortOrder,
     play_count: i32,
     play_time: Duration,
 }
-impl<'a> Playlist<'a> {
+impl Playlist {
     pub fn new() -> Self {
         Default::default()
     }
@@ -109,7 +109,7 @@ impl<'a> Playlist<'a> {
             .unwrap();
         m3u8.write_to(&mut file).unwrap();
     }
-    pub fn from_m3u8(path: &str) -> Result<Playlist<'a>, Error> {
+    pub fn from_m3u8(path: &str) -> Result<Playlist, Error> {
         let mut file = match File::open(path) {
             Ok(file) => file,
             Err(e) => return Err(e),
@@ -137,7 +137,7 @@ impl<'a> Playlist<'a> {
         &self.title
     }
     fn cover(&self) -> Option<&AlbumArt> {
-        match self.cover {
+        match &self.cover {
             Some(e) => Some(e),
             None => None,
         }
@@ -149,7 +149,7 @@ impl<'a> Playlist<'a> {
 
 
 
-impl Default for Playlist<'_> {
+impl Default for Playlist {
     fn default() -> Self {
         Playlist {
             title: String::default(),