// +--------------------------------------------------------------------------+
// | Copyright 2016 Matthew D. Steele <mdsteele@alum.mit.edu>                 |
// |                                                                          |
// | This file is part of System Syzygy.                                      |
// |                                                                          |
// | System Syzygy is free software: you can redistribute it and/or modify it |
// | under the terms of the GNU General Public License as published by the    |
// | Free Software Foundation, either version 3 of the License, or (at your   |
// | option) any later version.                                               |
// |                                                                          |
// | System Syzygy is distributed in the hope that it will be useful, but     |
// | WITHOUT ANY WARRANTY; without even the implied warranty of               |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        |
// | General Public License for details.                                      |
// |                                                                          |
// | You should have received a copy of the GNU General Public License along  |
// | with System Syzygy.  If not, see <http://www.gnu.org/licenses/>.         |
// +--------------------------------------------------------------------------+

use super::scenes;
use crate::elements::cross::{ClueDisplay, InputDisplay};
use crate::elements::{
    FadeStyle, ProgressBar, PuzzleCmd, PuzzleCore, PuzzleView,
};
use crate::gui::{Action, Canvas, Element, Event, Rect, Resources, Sound};
use crate::modes::SOLVED_INFO_TEXT;
use crate::save::{Direction, DoubleState, Game, PuzzleState};

// ========================================================================= //

pub struct View {
    core: PuzzleCore<()>,
    progress: ProgressBar,
    input: InputDisplay,
    clue: ClueDisplay,
    text_timer: i32,
    text_prefix: Option<String>,
}

impl View {
    pub fn new(
        resources: &mut Resources,
        visible: Rect,
        state: &DoubleState,
    ) -> View {
        let mut core = {
            let fade = (FadeStyle::LeftToRight, FadeStyle::LeftToRight);
            let intro = scenes::compile_intro_scene(resources);
            let outro = scenes::compile_outro_scene(resources);
            PuzzleCore::new(resources, visible, state, fade, intro, outro)
        };
        core.add_extra_scene(scenes::compile_ugrent_midscene(resources));
        View {
            core,
            progress: ProgressBar::new(
                (240, 160),
                Direction::East,
                96,
                (95, 95, 95),
            ),
            input: InputDisplay::new(resources, 112),
            clue: ClueDisplay::new(resources, 80),
            text_timer: 0,
            text_prefix: None,
        }
    }
}

impl Element<Game, PuzzleCmd> for View {
    fn draw(&self, game: &Game, canvas: &mut Canvas) {
        let state = &game.double_cross;
        self.core.draw_back_layer(canvas);
        self.input.draw(&(), canvas);
        if !state.is_solved() || self.text_timer > 0 {
            self.progress.draw(
                state.num_clues_done(),
                state.total_num_clues(),
                canvas,
            );
            self.clue.draw(&state.current_clue(), canvas);
        }
        self.core.draw_middle_layer(canvas);
        self.core.draw_front_layer(canvas, state);
    }

    fn handle_event(
        &mut self,
        event: &Event,
        game: &mut Game,
    ) -> Action<PuzzleCmd> {
        let state = &mut game.double_cross;
        let mut action = self.core.handle_event(event, state);
        if !action.should_stop() && event == &Event::ClockTick {
            if self.text_timer > 0 {
                self.text_timer -= 1;
                if self.text_timer == 0 {
                    if let Some(prefix) = self.text_prefix.take() {
                        self.input.set_text(prefix);
                    } else {
                        self.input.clear_text();
                        state.go_next();
                    }
                    if state.is_solved() {
                        self.core.begin_outro_scene();
                        action = action.and_return(PuzzleCmd::Save);
                    }
                    action.also_redraw();
                }
            }
        }
        if !action.should_stop() && self.text_timer == 0 {
            let subaction =
                self.clue.handle_event(event, &mut state.current_clue());
            if let Some(&next) = subaction.value() {
                if next {
                    state.go_next();
                    self.input.clear_text();
                } else {
                    state.go_prev();
                    self.input.clear_text();
                }
            }
            action.merge(subaction.but_no_value());
        }
        if !action.should_stop() && self.text_timer == 0 && !state.is_solved()
        {
            let subaction = self.input.handle_event(event, &mut ());
            if let Some(text) = subaction.value() {
                let (prefix, error, done) = state.try_text(text);
                if done {
                    self.input.set_text(prefix);
                    self.text_timer = 20;
                    action.also_play_sound(Sound::mid_puzzle_chime());
                } else if error {
                    self.text_timer = 5;
                    self.text_prefix = Some(prefix);
                    action.also_play_sound(Sound::talk_annoyed_hi());
                } else {
                    self.input.set_text(prefix);
                }
            }
            action.merge(subaction.but_no_value());
        }
        if !action.should_stop() && self.text_timer == 0 {
            self.core.begin_character_scene_on_click(event);
        }
        action
    }
}

impl PuzzleView for View {
    fn info_text(&self, game: &Game) -> &'static str {
        if game.double_cross.is_solved() {
            SOLVED_INFO_TEXT
        } else {
            INFO_BOX_TEXT
        }
    }

    fn undo(&mut self, _: &mut Game) {}

    fn redo(&mut self, _: &mut Game) {}

    fn reset(&mut self, game: &mut Game) {
        self.core.clear_undo_redo();
        game.double_cross.reset();
    }

    fn solve(&mut self, game: &mut Game) {
        game.double_cross.solve();
        self.core.begin_outro_scene();
    }

    fn drain_queue(&mut self) {
        for (kind, value) in self.core.drain_queue() {
            if kind == 0 {
                self.clue.set_visible(value != 0);
            } else if kind == 1 {
                if value == 0 {
                    self.input.clear_text();
                } else if value == 1 {
                    self.input.set_text("FALSE/TRUE".to_string());
                } else if value == 2 {
                    self.input.set_text("NEVER/ALWAYS".to_string());
                } else if value == 3 {
                    self.input.set_text("TNEITAPMI".to_string());
                }
            }
        }
    }
}

// ========================================================================= //

const INFO_BOX_TEXT: &str = "\
Your goal is to enter the word pairs hinted at by
the clues.  Each pair of words will be antonyms.

For each clue, type in the two words in order
(without any spaces or punctuation), using the
$M{on-screen }{}keyboard.

$M{Tap}{Click} the arrows to skip past a particular clue
and come back to it later.

$M{Tap}{Click} on a character in the scene to hear their
words of wisdom.";

// ========================================================================= //
