use crate::*;

pub struct MatrixControllers<'a> {
    post_record: &'a PostRecordController,
    osc: &'a OscController,
    persistence: &'a PersistenceManagerController,
    sample_rate: usize,
}

pub struct ColumnControllers<'a> {
    post_record: &'a PostRecordController,
    osc: &'a OscController,
    persistence: &'a PersistenceManagerController,
    sample_rate: usize,
    column: usize,
}

pub struct TrackControllers<'a> {
    post_record: &'a PostRecordController,
    osc: &'a OscController,
    persistence: &'a PersistenceManagerController,
    sample_rate: usize,
    column: usize,
    row: usize,
}

impl<'a> MatrixControllers<'a> {
    pub fn new(
        post_record: &'a PostRecordController,
        osc: &'a OscController,
        persistence: &'a PersistenceManagerController,
        sample_rate: usize,
    ) -> Self {
        Self {
            post_record,
            osc,
            persistence,
            sample_rate,
        }
    }

    pub fn to_column_controllers(&self, column: usize) -> ColumnControllers<'a> {
        ColumnControllers {
            post_record: self.post_record,
            osc: self.osc,
            persistence: self.persistence,
            sample_rate: self.sample_rate,
            column,
        }
    }

    pub fn try_recv_post_record_response(&self) -> Option<PostRecordResponse> {
        self.post_record.try_recv_response()
    }
}

impl<'a> ColumnControllers<'a> {
    pub fn to_track_controllers(&self, row: usize) -> TrackControllers<'a> {
        TrackControllers {
            post_record: self.post_record,
            osc: self.osc,
            persistence: self.persistence,
            sample_rate: self.sample_rate,
            column: self.column,
            row,
        }
    }

    pub fn send_column_beats_changed(&self, beats: usize) -> Result<()> {
        self.osc.column_beats_changed(self.column, beats)
    }

    pub fn send_column_beat_changed(&self, beat: usize) -> Result<()> {
        self.osc.column_beat_changed(self.column, beat)
    }
}

impl<'a> TrackControllers<'a> {
    pub fn new(
        post_record: &'a PostRecordController,
        osc: &'a OscController,
        persistence: &'a PersistenceManagerController,
        sample_rate: usize,
        column: usize,
        row: usize,
    ) -> Self {
        Self {
            post_record,
            osc,
            persistence,
            sample_rate,
            column,
            row,
        }
    }

    pub fn send_post_record_request(
        &self,
        chunk: Arc<AudioChunk>,
        sync_offset: usize,
    ) -> Result<()> {
        self.post_record
            .send_request(self.column, self.row, chunk, sync_offset, self.sample_rate)
    }

    pub fn send_state_update(&self, state: TrackState) -> Result<()> {
        self.osc.track_state_changed(self.column, self.row, state)
    }

    pub fn send_volume_update(&self, volume: f32) -> Result<()> {
        self.osc.track_volume_changed(self.column, self.row, volume)
    }

    pub fn update_track_volume(&self, volume: f32) -> Result<()> {
        self.persistence
            .update_track_volume(self.column, self.row, volume)
    }

    pub fn column(&self) -> usize {
        self.column
    }

    pub fn row(&self) -> usize {
        self.row
    }
}
