use std::fmt::Debug;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// A token with a normalized form (used for diffing) and an original form
/// (used when applying operations). Joinability flags control whether
/// adjacent insertions interleave or group.
///
/// UTF-8 compatible.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone)]
pub struct Token<T>
where
    T: PartialEq + Clone + Debug,
{
    /// The normalized form of the token used deriving the diff
    normalized: T,

    /// The original string, that should be inserted or deleted in the document
    original: String,

    /// Whether the token is semantically joinable with the previous token
    pub is_left_joinable: bool,

    /// Whether the token is semantically joinable with the next token
    pub is_right_joinable: bool,
}

/// Trivial implementation of Token when the normalized form is the same as the
/// original string
impl From<&str> for Token<String> {
    fn from(text: &str) -> Self {
        Token::new(text.to_owned(), text.to_owned(), true, true)
    }
}

impl<T> Token<T>
where
    T: PartialEq + Clone + Debug,
{
    pub fn new(
        normalized: T,
        original: String,
        is_left_joinable: bool,
        is_right_joinable: bool,
    ) -> Self {
        Token {
            normalized,
            original,
            is_left_joinable,
            is_right_joinable,
        }
    }

    pub fn original(&self) -> &str {
        &self.original
    }

    pub fn set_normalized(&mut self, normalized: T) {
        self.normalized = normalized;
    }

    pub fn normalized(&self) -> &T {
        &self.normalized
    }

    pub fn get_original_length(&self) -> usize {
        self.original.chars().count()
    }
}

impl<T> PartialEq for Token<T>
where
    T: PartialEq + Clone + Debug,
{
    fn eq(&self, other: &Self) -> bool {
        self.normalized == other.normalized
    }
}
