use crate::refs::format_refs::{
    fmt_cell_range, fmt_cell_ref, fmt_col, fmt_col_range, fmt_row, fmt_row_range,
};
use crate::refs::parser::CRCode::{CRCellRange, CRCellRef, CRColRange, CRRowRange};
use crate::refs::parser::{CRCode, KTokenizerError};
use crate::OdsError;
use kparse::provider::StdTracker;
use kparse::Track;
use std::fmt;
use std::fmt::{Display, Formatter, Write};
mod format;
mod parser;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CRow {
    row_abs: bool,
    row: u32,
}
impl CRow {
    pub(crate) fn row(&self) -> u32 {
        self.row
    }
    pub(crate) fn row_abs(&self) -> bool {
        self.row_abs
    }
}
impl Display for CRow {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        fmt_row(f, self)
    }
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CCol {
    col_abs: bool,
    col: u32,
}
impl CCol {
    pub(crate) fn col(&self) -> u32 {
        self.col
    }
    pub(crate) fn col_abs(&self) -> bool {
        self.col_abs
    }
}
impl Display for CCol {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        fmt_col(f, self)
    }
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct CellRef {
    iri: Option<String>,
    table: Option<String>,
    row: CRow,
    col: CCol,
}
impl CellRef {
    pub fn new_all(
        iri: Option<String>,
        table: Option<String>,
        row_abs: bool,
        row: u32,
        col_abs: bool,
        col: u32,
    ) -> Self {
        Self {
            iri,
            table,
            row: CRow { row_abs, row },
            col: CCol { col_abs, col },
        }
    }
    pub fn new() -> Self {
        Default::default()
    }
    pub fn local(row: u32, col: u32) -> Self {
        Self {
            iri: None,
            table: None,
            row: CRow {
                row_abs: false,
                row,
            },
            col: CCol {
                col_abs: false,
                col,
            },
        }
    }
    pub fn remote<S: Into<String>>(table: S, row: u32, col: u32) -> Self {
        Self {
            iri: None,
            table: Some(table.into()),
            row: CRow {
                row_abs: false,
                row,
            },
            col: CCol {
                col_abs: false,
                col,
            },
        }
    }
    pub fn set_iri<S: Into<String>>(&mut self, iri: S) {
        self.iri = Some(iri.into());
    }
    pub fn iri(&self) -> Option<&String> {
        self.iri.as_ref()
    }
    pub fn set_table<S: Into<String>>(&mut self, table: S) {
        self.table = Some(table.into());
    }
    pub fn table(&self) -> Option<&String> {
        self.table.as_ref()
    }
    pub fn set_row(&mut self, row: u32) {
        self.row.row = row;
    }
    pub fn row(&self) -> u32 {
        self.row.row
    }
    pub fn set_row_abs(&mut self, abs: bool) {
        self.row.row_abs = abs;
    }
    pub fn row_abs(&self) -> bool {
        self.row.row_abs
    }
    pub fn set_col(&mut self, col: u32) {
        self.col.col = col;
    }
    pub fn col(&self) -> u32 {
        self.col.col
    }
    pub fn set_col_abs(&mut self, abs: bool) {
        self.col.col_abs = abs;
    }
    pub fn col_abs(&self) -> bool {
        self.col.col_abs
    }
    pub fn to_formula(&self) -> String {
        let mut buf = String::new();
        buf.push('[');
        let _ = fmt_cell_ref(&mut buf, self);
        buf.push(']');
        buf
    }
    pub fn absolute(mut self) -> Self {
        self.col.col_abs = true;
        self.row.row_abs = true;
        self
    }
    pub fn absolute_row(mut self) -> Self {
        self.row.row_abs = true;
        self
    }
    pub fn absolute_col(mut self) -> Self {
        self.col.col_abs = true;
        self
    }
}
impl TryFrom<&str> for CellRef {
    type Error = OdsError;
    fn try_from(s: &str) -> Result<Self, Self::Error> {
        parse_cellref(s)
    }
}
impl Display for CellRef {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        fmt_cell_ref(f, self)
    }
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct CellRange {
    iri: Option<String>,
    from_table: Option<String>,
    from_row: CRow,
    from_col: CCol,
    to_table: Option<String>,
    to_row: CRow,
    to_col: CCol,
}
impl CellRange {
    #[allow(clippy::too_many_arguments)]
    pub fn new_all(
        iri: Option<String>,
        from_table: Option<String>,
        from_row_abs: bool,
        from_row: u32,
        from_col_abs: bool,
        from_col: u32,
        to_table: Option<String>,
        to_row_abs: bool,
        to_row: u32,
        to_col_abs: bool,
        to_col: u32,
    ) -> Self {
        Self {
            iri,
            from_table,
            from_row: CRow {
                row_abs: from_row_abs,
                row: from_row,
            },
            from_col: CCol {
                col_abs: from_col_abs,
                col: from_col,
            },
            to_table,
            to_row: CRow {
                row_abs: to_row_abs,
                row: to_row,
            },
            to_col: CCol {
                col_abs: to_col_abs,
                col: to_col,
            },
        }
    }
    pub fn new() -> Self {
        Default::default()
    }
    pub fn local(row: u32, col: u32, to_row: u32, to_col: u32) -> Self {
        assert!(row <= to_row);
        assert!(col <= to_col);
        Self {
            iri: None,
            from_table: None,
            from_row: CRow {
                row_abs: false,
                row,
            },
            from_col: CCol {
                col_abs: false,
                col,
            },
            to_table: None,
            to_row: CRow {
                row_abs: false,
                row: to_row,
            },
            to_col: CCol {
                col_abs: false,
                col: to_col,
            },
        }
    }
    pub fn remote<S: Into<String>>(table: S, row: u32, col: u32, to_row: u32, to_col: u32) -> Self {
        assert!(row <= to_row);
        assert!(col <= to_col);
        Self {
            iri: None,
            from_table: Some(table.into()),
            from_row: CRow {
                row_abs: false,
                row,
            },
            from_col: CCol {
                col_abs: false,
                col,
            },
            to_table: None,
            to_row: CRow {
                row_abs: false,
                row: to_row,
            },
            to_col: CCol {
                col_abs: false,
                col: to_col,
            },
        }
    }
    pub fn origin_span(row: u32, col: u32, span: (u32, u32)) -> Self {
        assert!(span.0 > 0);
        assert!(span.1 > 0);
        Self {
            iri: None,
            from_table: None,
            from_row: CRow {
                row_abs: false,
                row,
            },
            from_col: CCol {
                col_abs: false,
                col,
            },
            to_table: None,
            to_row: CRow {
                row_abs: false,
                row: row + span.0 - 1,
            },
            to_col: CCol {
                col_abs: false,
                col: col + span.1 - 1,
            },
        }
    }
    pub fn set_iri<S: Into<String>>(&mut self, iri: S) {
        self.iri = Some(iri.into());
    }
    pub fn iri(&self) -> Option<&String> {
        self.iri.as_ref()
    }
    pub fn set_table<S: Into<String>>(&mut self, table: S) {
        self.from_table = Some(table.into());
    }
    pub fn table(&self) -> Option<&String> {
        self.from_table.as_ref()
    }
    pub fn set_row(&mut self, row: u32) {
        self.from_row.row = row;
    }
    pub fn row(&self) -> u32 {
        self.from_row.row
    }
    pub fn set_row_abs(&mut self, abs: bool) {
        self.from_row.row_abs = abs;
    }
    pub fn row_abs(&self) -> bool {
        self.from_row.row_abs
    }
    pub fn set_col(&mut self, col: u32) {
        self.from_col.col = col;
    }
    pub fn col(&self) -> u32 {
        self.from_col.col
    }
    pub fn set_col_abs(&mut self, abs: bool) {
        self.from_col.col_abs = abs;
    }
    pub fn col_abs(&self) -> bool {
        self.from_col.col_abs
    }
    pub fn set_to_table<S: Into<String>>(&mut self, table: S) {
        self.to_table = Some(table.into());
    }
    pub fn to_table(&self) -> Option<&String> {
        self.to_table.as_ref()
    }
    pub fn set_to_row(&mut self, to_row: u32) {
        self.to_row.row = to_row;
    }
    pub fn to_row(&self) -> u32 {
        self.to_row.row
    }
    pub fn set_to_row_abs(&mut self, abs: bool) {
        self.to_row.row_abs = abs;
    }
    pub fn to_row_abs(&self) -> bool {
        self.to_row.row_abs
    }
    pub fn set_to_col(&mut self, to_col: u32) {
        self.to_col.col = to_col;
    }
    pub fn to_col(&self) -> u32 {
        self.to_col.col
    }
    pub fn set_to_col_abs(&mut self, abs: bool) {
        self.to_col.col_abs = abs;
    }
    pub fn to_col_abs(&self) -> bool {
        self.to_col.col_abs
    }
    pub fn to_formula(&self) -> String {
        let mut buf = String::new();
        buf.push('[');
        let _ = fmt_cell_range(&mut buf, self);
        buf.push(']');
        buf
    }
    pub fn absolute(mut self) -> Self {
        self.from_col.col_abs = true;
        self.from_row.row_abs = true;
        self.to_col.col_abs = true;
        self.to_row.row_abs = true;
        self
    }
    pub fn absolute_rows(mut self) -> Self {
        self.from_row.row_abs = true;
        self.to_row.row_abs = true;
        self
    }
    pub fn absolute_cols(mut self) -> Self {
        self.from_col.col_abs = true;
        self.to_col.col_abs = true;
        self
    }
    pub fn contains(&self, row: u32, col: u32) -> bool {
        row >= self.from_row.row
            && row <= self.to_row.row
            && col >= self.from_col.col
            && col <= self.to_col.col
    }
    pub fn out_looped(&self, row: u32, col: u32) -> bool {
        row > self.to_row.row || row == self.to_row.row && col > self.to_col.col
    }
}
impl TryFrom<&str> for CellRange {
    type Error = OdsError;
    fn try_from(s: &str) -> Result<Self, Self::Error> {
        parse_cellrange(s)
    }
}
impl Display for CellRange {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        fmt_cell_range(f, self)
    }
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ColRange {
    iri: Option<String>,
    from_table: Option<String>,
    from_col: CCol,
    to_table: Option<String>,
    to_col: CCol,
}
impl ColRange {
    pub fn new_all(
        iri: Option<String>,
        from_table: Option<String>,
        from_col_abs: bool,
        from_col: u32,
        to_table: Option<String>,
        to_col_abs: bool,
        to_col: u32,
    ) -> Self {
        Self {
            iri,
            from_table,
            from_col: CCol {
                col_abs: from_col_abs,
                col: from_col,
            },
            to_table,
            to_col: CCol {
                col_abs: to_col_abs,
                col: to_col,
            },
        }
    }
    pub fn new(from_col: u32, to_col: u32) -> Self {
        assert!(from_col <= to_col);
        Self {
            iri: None,
            from_table: None,
            from_col: CCol {
                col_abs: false,
                col: from_col,
            },
            to_table: None,
            to_col: CCol {
                col_abs: false,
                col: to_col,
            },
        }
    }
    pub fn set_iri<S: Into<String>>(&mut self, iri: S) {
        self.iri = Some(iri.into());
    }
    pub fn iri(&self) -> Option<&String> {
        self.iri.as_ref()
    }
    pub fn set_table<S: Into<String>>(&mut self, table: S) {
        self.from_table = Some(table.into());
    }
    pub fn table(&self) -> Option<&String> {
        self.from_table.as_ref()
    }
    pub fn set_col(&mut self, col: u32) {
        self.from_col.col = col;
    }
    pub fn col(&self) -> u32 {
        self.from_col.col
    }
    pub fn set_col_abs(&mut self, abs: bool) {
        self.from_col.col_abs = abs;
    }
    pub fn col_abs(&self) -> bool {
        self.from_col.col_abs
    }
    pub fn set_to_table<S: Into<String>>(&mut self, table: S) {
        self.to_table = Some(table.into());
    }
    pub fn to_table(&self) -> Option<&String> {
        self.to_table.as_ref()
    }
    pub fn set_to_col(&mut self, to_col: u32) {
        self.to_col.col = to_col;
    }
    pub fn to_col(&self) -> u32 {
        self.to_col.col
    }
    pub fn set_to_col_abs(&mut self, abs: bool) {
        self.to_col.col_abs = abs;
    }
    pub fn to_col_abs(&self) -> bool {
        self.to_col.col_abs
    }
    pub fn to_formula(&self) -> String {
        let mut buf = String::new();
        buf.push('[');
        let _ = fmt_col_range(&mut buf, self);
        buf.push(']');
        buf
    }
    pub fn absolute(mut self) -> Self {
        self.from_col.col_abs = true;
        self.to_col.col_abs = true;
        self
    }
    pub fn contains(&self, col: u32) -> bool {
        col >= self.from_col.col && col <= self.to_col.col
    }
}
impl TryFrom<&str> for ColRange {
    type Error = OdsError;
    fn try_from(s: &str) -> Result<Self, Self::Error> {
        parse_colrange(s)
    }
}
impl Display for ColRange {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        fmt_col_range(f, self)
    }
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct RowRange {
    iri: Option<String>,
    from_table: Option<String>,
    from_row: CRow,
    to_table: Option<String>,
    to_row: CRow,
}
impl RowRange {
    pub fn new_all(
        iri: Option<String>,
        from_table: Option<String>,
        from_row_abs: bool,
        from_row: u32,
        to_table: Option<String>,
        to_row_abs: bool,
        to_row: u32,
    ) -> Self {
        Self {
            iri,
            from_table,
            from_row: CRow {
                row_abs: from_row_abs,
                row: from_row,
            },
            to_table,
            to_row: CRow {
                row_abs: to_row_abs,
                row: to_row,
            },
        }
    }
    pub fn new(from_row: u32, to_row: u32) -> Self {
        assert!(from_row <= to_row);
        Self {
            iri: None,
            from_table: None,
            from_row: CRow {
                row_abs: false,
                row: from_row,
            },
            to_table: None,
            to_row: CRow {
                row_abs: false,
                row: to_row,
            },
        }
    }
    pub fn set_iri<S: Into<String>>(&mut self, iri: S) {
        self.iri = Some(iri.into());
    }
    pub fn iri(&self) -> Option<&String> {
        self.iri.as_ref()
    }
    pub fn set_table<S: Into<String>>(&mut self, table: S) {
        self.from_table = Some(table.into());
    }
    pub fn table(&self) -> Option<&String> {
        self.from_table.as_ref()
    }
    pub fn row(&self) -> u32 {
        self.from_row.row
    }
    pub fn set_row(&mut self, row: u32) {
        self.from_row.row = row;
    }
    pub fn set_row_abs(&mut self, abs: bool) {
        self.from_row.row_abs = abs;
    }
    pub fn row_abs(&self) -> bool {
        self.from_row.row_abs
    }
    pub fn set_to_table<S: Into<String>>(&mut self, table: S) {
        self.to_table = Some(table.into());
    }
    pub fn to_table(&self) -> Option<&String> {
        self.to_table.as_ref()
    }
    pub fn to_row(&self) -> u32 {
        self.to_row.row
    }
    pub fn set_to_row(&mut self, row: u32) {
        self.to_row.row = row;
    }
    pub fn set_to_row_abs(&mut self, abs: bool) {
        self.to_row.row_abs = abs;
    }
    pub fn to_row_abs(&self) -> bool {
        self.to_row.row_abs
    }
    pub fn to_formula(&self) -> String {
        let mut buf = String::new();
        buf.push('[');
        let _ = fmt_row_range(&mut buf, self);
        buf.push(']');
        buf
    }
    pub fn absolute(mut self) -> Self {
        self.from_row.row_abs = true;
        self.to_row.row_abs = true;
        self
    }
    pub fn contains(&self, row: u32) -> bool {
        row >= self.from_row.row && row <= self.to_row.row
    }
}
impl TryFrom<&str> for RowRange {
    type Error = OdsError;
    fn try_from(s: &str) -> Result<Self, Self::Error> {
        parse_rowrange(s)
    }
}
impl Display for RowRange {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        fmt_row_range(f, self)
    }
}
mod format_refs {
    use crate::refs::format::{fmt_abs, fmt_col_name, fmt_row_name};
    use crate::refs::{CCol, CRow};
    use crate::{CellRange, CellRef, ColRange, RowRange};
    use std::fmt;
    pub(crate) fn fmt_row(f: &mut impl fmt::Write, row: &CRow) -> fmt::Result {
        fmt_abs(f, row.row_abs())?;
        fmt_row_name(f, row.row())?;
        Ok(())
    }
    pub(crate) fn fmt_col(f: &mut impl fmt::Write, col: &CCol) -> fmt::Result {
        fmt_abs(f, col.col_abs())?;
        fmt_col_name(f, col.col())?;
        Ok(())
    }
    pub(crate) fn fmt_cell_ref(f: &mut impl fmt::Write, cell_ref: &CellRef) -> fmt::Result {
        fmt_iri(f, cell_ref.iri())?;
        if let Some(sheet) = cell_ref.table().as_ref() {
            fmt_table_name(
                f,
                sheet,
                cell_ref.iri().is_some() || cell_ref.col_abs() || cell_ref.row_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_col(f, &cell_ref.col)?;
        fmt_row(f, &cell_ref.row)?;
        Ok(())
    }
    pub(crate) fn fmt_cell_range(f: &mut impl fmt::Write, cell_range: &CellRange) -> fmt::Result {
        fmt_iri(f, cell_range.iri())?;
        if let Some(table) = cell_range.table().as_ref() {
            fmt_table_name(
                f,
                table,
                cell_range.iri().is_some()
                    || cell_range.from_row.row_abs()
                    || cell_range.from_col.col_abs()
                    || cell_range.to_row.row_abs()
                    || cell_range.to_col.col_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_col(f, &cell_range.from_col)?;
        fmt_row(f, &cell_range.from_row)?;
        write!(f, ":")?;
        if let Some(to_table) = cell_range.to_table().as_ref() {
            fmt_table_name(
                f,
                to_table,
                cell_range.iri().is_some()
                    || cell_range.from_row.row_abs()
                    || cell_range.from_col.col_abs()
                    || cell_range.to_row.row_abs()
                    || cell_range.to_col.col_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_col(f, &cell_range.to_col)?;
        fmt_row(f, &cell_range.to_row)?;
        Ok(())
    }
    pub(crate) fn fmt_col_range(f: &mut impl fmt::Write, col_range: &ColRange) -> fmt::Result {
        fmt_iri(f, col_range.iri())?;
        if let Some(sheet) = col_range.table().as_ref() {
            fmt_table_name(
                f,
                sheet,
                col_range.iri().is_some() || col_range.col_abs() || col_range.to_col_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_col(f, &col_range.from_col)?;
        write!(f, ":")?;
        if let Some(to_sheet) = col_range.to_table().as_ref() {
            fmt_table_name(
                f,
                to_sheet,
                col_range.iri().is_some() || col_range.col_abs() || col_range.to_col_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_col(f, &col_range.to_col)?;
        Ok(())
    }
    pub(crate) fn fmt_row_range(f: &mut impl fmt::Write, row_range: &RowRange) -> fmt::Result {
        fmt_iri(f, row_range.iri())?;
        if let Some(table) = row_range.table().as_ref() {
            fmt_table_name(
                f,
                table,
                row_range.iri().is_some() || row_range.row_abs() || row_range.to_row_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_row(f, &row_range.from_row)?;
        write!(f, ":")?;
        if let Some(to_table) = row_range.to_table().as_ref() {
            fmt_table_name(
                f,
                to_table,
                row_range.iri().is_some() || row_range.row_abs() || row_range.to_row_abs(),
            )?;
        }
        write!(f, ".")?;
        fmt_row(f, &row_range.to_row)?;
        Ok(())
    }
    pub(crate) fn fmt_iri(f: &mut impl fmt::Write, iri: Option<&String>) -> fmt::Result {
        if let Some(iri) = iri {
            write!(f, "'")?;
            write!(f, "{}", &iri.replace('\'', "''"))?;
            write!(f, "'")?;
            write!(f, "#")?;
        }
        Ok(())
    }
    pub(crate) fn fmt_table_name(
        f: &mut impl fmt::Write,
        table_name: &str,
        abs: bool,
    ) -> fmt::Result {
        fmt_abs(f, abs)?;
        if table_name.contains(|c| c == '\'' || c == ' ' || c == '.') {
            write!(f, "'")?;
            write!(f, "{}", &table_name.replace('\'', "''"))?;
            write!(f, "'")?;
        } else {
            write!(f, "{}", table_name)?;
        }
        Ok(())
    }
}
pub fn parse_cellref(buf: &str) -> Result<CellRef, OdsError> {
    let trk: StdTracker<CRCode, _> = Track::new_tracker();
    let span = Track::new_span(&trk, buf);
    let (rest, tok) = parser::parse_cell_ref(span)?;
    if rest.len() > 0 {
        Err(nom::Err::Error(KTokenizerError::new(CRCellRef, rest)))?
    } else {
        Ok(tok)
    }
}
pub fn parse_cellrange(buf: &str) -> Result<CellRange, OdsError> {
    let trk: StdTracker<CRCode, _> = Track::new_tracker();
    let span = Track::new_span(&trk, buf);
    let (rest, tok) = parser::parse_cell_range(span)?;
    if rest.len() > 0 {
        Err(nom::Err::Error(KTokenizerError::new(CRCellRange, rest)))?
    } else {
        Ok(tok)
    }
}
pub fn parse_colrange(buf: &str) -> Result<ColRange, OdsError> {
    let trk: StdTracker<CRCode, _> = Track::new_tracker();
    let span = Track::new_span(&trk, buf);
    let (rest, tok) = parser::parse_col_range(span)?;
    if rest.len() > 0 {
        Err(nom::Err::Error(KTokenizerError::new(CRColRange, rest)))?
    } else {
        Ok(tok)
    }
}
pub fn parse_rowrange(buf: &str) -> Result<RowRange, OdsError> {
    let trk: StdTracker<CRCode, _> = Track::new_tracker();
    let span = Track::new_span(&trk, buf);
    let (rest, tok) = parser::parse_row_range(span)?;
    if rest.len() > 0 {
        Err(nom::Err::Error(KTokenizerError::new(CRRowRange, rest)))?
    } else {
        Ok(tok)
    }
}
pub fn parse_cellranges(buf: &str) -> Result<Option<Vec<CellRange>>, OdsError> {
    let trk: StdTracker<CRCode, _> = Track::new_tracker();
    let span = Track::new_span(&trk, buf);
    match parser::parse_cell_range_list(span) {
        Ok((_, ranges)) => Ok(ranges),
        Err(err) => Err(err.into()),
    }
}
pub fn cellranges_string(vec: &[CellRange]) -> String {
    let mut buf = String::new();
    for (i, range) in vec.iter().enumerate() {
        if i > 0 {
            let _ = write!(buf, " ");
        }
        let _ = write!(buf, "{}", range);
    }
    buf
}