-- | Cell references & indexing.
module Music.Theory.Array.Cell_Ref where

import Data.Char {- base -}
import Data.Function {- base -}
import Data.Maybe {- base -}

import qualified Data.Array as A {- array -}

-- | @A@ indexed case-insensitive column references.  The column following @Z@ is @AA@.
newtype Column_Ref = Column_Ref {Column_Ref -> String
column_ref_string :: String}

{-
--import Data.String {- base -}
instance IsString Column_Ref where fromString = Column_Ref
-}

instance Read Column_Ref where readsPrec :: Row_Ref -> ReadS Column_Ref
readsPrec Row_Ref
_ String
s = [(String -> Column_Ref
Column_Ref String
s,[])]
instance Show Column_Ref where show :: Column_Ref -> String
show = Column_Ref -> String
column_ref_string
instance Eq Column_Ref where == :: Column_Ref -> Column_Ref -> Bool
(==) = forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Column_Ref -> Row_Ref
column_index
instance Ord Column_Ref where compare :: Column_Ref -> Column_Ref -> Ordering
compare = forall a. Ord a => a -> a -> Ordering
compare forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Column_Ref -> Row_Ref
column_index

instance Enum Column_Ref where
    fromEnum :: Column_Ref -> Row_Ref
fromEnum = Column_Ref -> Row_Ref
column_index
    toEnum :: Row_Ref -> Column_Ref
toEnum = Row_Ref -> Column_Ref
column_ref

instance A.Ix Column_Ref where
    range :: (Column_Ref, Column_Ref) -> [Column_Ref]
range = (Column_Ref, Column_Ref) -> [Column_Ref]
column_range
    index :: (Column_Ref, Column_Ref) -> Column_Ref -> Row_Ref
index = (Column_Ref, Column_Ref) -> Column_Ref -> Row_Ref
interior_column_index
    inRange :: (Column_Ref, Column_Ref) -> Column_Ref -> Bool
inRange = (Column_Ref, Column_Ref) -> Column_Ref -> Bool
column_in_range
    rangeSize :: (Column_Ref, Column_Ref) -> Row_Ref
rangeSize = (Column_Ref, Column_Ref) -> Row_Ref
column_range_size

-- | Inclusive range of column references.
type Column_Range = (Column_Ref,Column_Ref)

-- | @1@-indexed row reference.
type Row_Ref = Int

-- | Zero index of 'Row_Ref'.
row_index :: Row_Ref -> Int
row_index :: Row_Ref -> Row_Ref
row_index Row_Ref
r = Row_Ref
r forall a. Num a => a -> a -> a
- Row_Ref
1

-- | Inclusive range of row references.
type Row_Range = (Row_Ref,Row_Ref)

-- | Cell reference, column then row.
type Cell_Ref = (Column_Ref,Row_Ref)

-- | Inclusive range of cell references.
type Cell_Range = (Cell_Ref,Cell_Ref)

-- | Case folding letter to index function.  Only valid for ASCII letters.
--
-- > map letter_index ['A' .. 'Z'] == [0 .. 25]
-- > map letter_index ['a','d' .. 'm'] == [0,3 .. 12]
letter_index :: Char -> Int
letter_index :: Char -> Row_Ref
letter_index Char
c = forall a. Enum a => a -> Row_Ref
fromEnum (Char -> Char
toUpper Char
c) forall a. Num a => a -> a -> a
- forall a. Enum a => a -> Row_Ref
fromEnum Char
'A'

-- | Inverse of 'letter_index'.
--
-- > map index_letter [0,3 .. 12] == ['A','D' .. 'M']
index_letter :: Int -> Char
index_letter :: Row_Ref -> Char
index_letter Row_Ref
i = forall a. Enum a => Row_Ref -> a
toEnum (Row_Ref
i forall a. Num a => a -> a -> a
+ forall a. Enum a => a -> Row_Ref
fromEnum Char
'A')

-- | Translate column reference to @0@-index.
--
-- > :set -XOverloadedStrings
-- > map column_index ["A","c","z","ac","XYZ"] == [0,2,25,28,17575]
column_index :: Column_Ref -> Int
column_index :: Column_Ref -> Row_Ref
column_index (Column_Ref String
c) =
    let m :: [Row_Ref]
m = forall a. (a -> a) -> a -> [a]
iterate (forall a. Num a => a -> a -> a
* Row_Ref
26) Row_Ref
1
        i :: [Row_Ref]
i = forall a. [a] -> [a]
reverse (forall a b. (a -> b) -> [a] -> [b]
map Char -> Row_Ref
letter_index String
c)
    in forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall a. Num a => a -> a -> a
(*) [Row_Ref]
m (forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall a. Num a => a -> a -> a
(+) [Row_Ref
0..] [Row_Ref]
i))

-- | Column reference to interior index within specified range.
--   Type specialised 'Data.Ix.index'.
--
-- > map (Data.Ix.index ('A','Z')) ['A','C','Z'] == [0,2,25]
-- > map (interior_column_index ("A","Z")) ["A","C","Z"] == [0,2,25]
--
-- > map (Data.Ix.index ('B','C')) ['B','C'] == [0,1]
-- > map (interior_column_index ("B","C")) ["B","C"] == [0,1]
interior_column_index :: Column_Range -> Column_Ref -> Int
interior_column_index :: (Column_Ref, Column_Ref) -> Column_Ref -> Row_Ref
interior_column_index (Column_Ref
l,Column_Ref
r) Column_Ref
c =
    let n :: Row_Ref
n = Column_Ref -> Row_Ref
column_index Column_Ref
c
        l' :: Row_Ref
l' = Column_Ref -> Row_Ref
column_index Column_Ref
l
        r' :: Row_Ref
r' = Column_Ref -> Row_Ref
column_index Column_Ref
r
    in if Row_Ref
n forall a. Ord a => a -> a -> Bool
> Row_Ref
r'
       then forall a. HasCallStack => String -> a
error (forall a. Show a => a -> String
show (String
"interior_column_index",Column_Ref
l,Column_Ref
r,Column_Ref
c))
       else Row_Ref
n forall a. Num a => a -> a -> a
- Row_Ref
l'

-- | Inverse of 'column_index'.
--
-- > let c = ["A","Z","AA","AZ","BA","BZ","CA"]
-- > map column_ref [0,25,26,51,52,77,78] == c
--
-- > column_ref (0+25+1+25+1+25+1) == "CA"
column_ref :: Int -> Column_Ref
column_ref :: Row_Ref -> Column_Ref
column_ref =
    let rec :: Row_Ref -> String
rec Row_Ref
n = case Row_Ref
n forall a. Integral a => a -> a -> (a, a)
`quotRem` Row_Ref
26 of
                  (Row_Ref
0,Row_Ref
r) -> [Row_Ref -> Char
index_letter Row_Ref
r]
                  (Row_Ref
q,Row_Ref
r) -> Row_Ref -> Char
index_letter (Row_Ref
q forall a. Num a => a -> a -> a
- Row_Ref
1) forall a. a -> [a] -> [a]
: Row_Ref -> String
rec Row_Ref
r
    in String -> Column_Ref
Column_Ref forall b c a. (b -> c) -> (a -> b) -> a -> c
. Row_Ref -> String
rec

-- | Type specialised 'pred'.
--
-- > column_ref_pred "DF" == "DE"
column_ref_pred :: Column_Ref -> Column_Ref
column_ref_pred :: Column_Ref -> Column_Ref
column_ref_pred = forall a. Enum a => a -> a
pred

-- | Type specialised 'succ'.
--
-- > column_ref_succ "DE" == "DF"
column_ref_succ :: Column_Ref -> Column_Ref
column_ref_succ :: Column_Ref -> Column_Ref
column_ref_succ = forall a. Enum a => a -> a
succ

-- | Bimap of 'column_index'.
--
-- > column_indices ("b","p") == (1,15)
-- > column_indices ("B","IT") == (1,253)
column_indices :: Column_Range -> (Int,Int)
column_indices :: (Column_Ref, Column_Ref) -> (Row_Ref, Row_Ref)
column_indices =
    let bimap :: (t -> b) -> (t, t) -> (b, b)
bimap t -> b
f (t
i,t
j) = (t -> b
f t
i,t -> b
f t
j)
    in forall {t} {b}. (t -> b) -> (t, t) -> (b, b)
bimap Column_Ref -> Row_Ref
column_index

-- | Type specialised 'Data.Ix.range'.
--
-- > column_range ("L","R") == ["L","M","N","O","P","Q","R"]
-- > Data.Ix.range ('L','R') == "LMNOPQR"
column_range :: Column_Range -> [Column_Ref]
column_range :: (Column_Ref, Column_Ref) -> [Column_Ref]
column_range (Column_Ref, Column_Ref)
rng =
    let (Row_Ref
l,Row_Ref
r) = (Column_Ref, Column_Ref) -> (Row_Ref, Row_Ref)
column_indices (Column_Ref, Column_Ref)
rng
    in forall a b. (a -> b) -> [a] -> [b]
map Row_Ref -> Column_Ref
column_ref [Row_Ref
l .. Row_Ref
r]

-- | Type specialised 'Data.Ix.inRange'.
--
-- > map (column_in_range ("L","R")) ["A","N","Z"] == [False,True,False]
-- > map (column_in_range ("L","R")) ["L","N","R"] == [True,True,True]
--
-- > map (Data.Ix.inRange ('L','R')) ['A','N','Z'] == [False,True,False]
-- > map (Data.Ix.inRange ('L','R')) ['L','N','R'] == [True,True,True]
column_in_range :: Column_Range -> Column_Ref -> Bool
column_in_range :: (Column_Ref, Column_Ref) -> Column_Ref -> Bool
column_in_range (Column_Ref, Column_Ref)
rng Column_Ref
c =
    let (Row_Ref
l,Row_Ref
r) = (Column_Ref, Column_Ref) -> (Row_Ref, Row_Ref)
column_indices (Column_Ref, Column_Ref)
rng
        k :: Row_Ref
k = Column_Ref -> Row_Ref
column_index Column_Ref
c
    in Row_Ref
k forall a. Ord a => a -> a -> Bool
>= Row_Ref
l Bool -> Bool -> Bool
&& Row_Ref
k forall a. Ord a => a -> a -> Bool
<= Row_Ref
r

-- | Type specialised 'Data.Ix.rangeSize'.
--
-- > map column_range_size [("A","Z"),("AA","ZZ")] == [26,26 * 26]
-- > Data.Ix.rangeSize ('A','Z') == 26
column_range_size :: Column_Range -> Int
column_range_size :: (Column_Ref, Column_Ref) -> Row_Ref
column_range_size = (forall a. Num a => a -> a -> a
+ Row_Ref
1) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => a -> a
negate forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (-) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Column_Ref, Column_Ref) -> (Row_Ref, Row_Ref)
column_indices

-- | Type specialised 'Data.Ix.range'.
row_range :: Row_Range -> [Row_Ref]
row_range :: (Row_Ref, Row_Ref) -> [Row_Ref]
row_range = forall a. Ix a => (a, a) -> [a]
A.range

-- | The standard uppermost leftmost cell reference, @A1@.
--
-- > Just cell_ref_minima == parse_cell_ref "A1"
cell_ref_minima :: Cell_Ref
cell_ref_minima :: Cell_Ref
cell_ref_minima = (String -> Column_Ref
Column_Ref String
"A",Row_Ref
1)

-- | Cell reference parser for standard notation of (column,row).
--
-- > parse_cell_ref "CC348" == Just ("CC",348)
parse_cell_ref :: String -> Maybe Cell_Ref
parse_cell_ref :: String -> Maybe Cell_Ref
parse_cell_ref String
s =
    case forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isUpper String
s of
      ([],String
_) -> forall a. Maybe a
Nothing
      (String
c,String
r) -> case forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit String
r of
                 (String
n,[]) -> forall a. a -> Maybe a
Just (String -> Column_Ref
Column_Ref String
c,forall a. Read a => String -> a
read String
n)
                 (String, String)
_ -> forall a. Maybe a
Nothing

-- | 'isJust' of 'parse_cell_ref'.
is_cell_ref :: String -> Bool
is_cell_ref :: String -> Bool
is_cell_ref = forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe Cell_Ref
parse_cell_ref

-- | 'fromJust' of 'parse_cell_ref'
parse_cell_ref_err :: String -> Cell_Ref
parse_cell_ref_err :: String -> Cell_Ref
parse_cell_ref_err = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"parse_cell_ref") forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe Cell_Ref
parse_cell_ref

-- | Cell reference pretty printer.
--
-- > cell_ref_pp ("CC",348) == "CC348"
cell_ref_pp :: Cell_Ref -> String
cell_ref_pp :: Cell_Ref -> String
cell_ref_pp (Column_Ref String
c,Row_Ref
r) = String
c forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Row_Ref
r

-- | Translate cell reference to @0@-indexed pair.
--
-- > cell_index ("CC",348) == (80,347)
-- > Data.Ix.index ((Column_Ref "AA",1),(Column_Ref "ZZ",999)) (Column_Ref "CC",348) == 54293
cell_index :: Cell_Ref -> (Int,Int)
cell_index :: Cell_Ref -> (Row_Ref, Row_Ref)
cell_index (Column_Ref
c,Row_Ref
r) = (Column_Ref -> Row_Ref
column_index Column_Ref
c,Row_Ref -> Row_Ref
row_index Row_Ref
r)

-- | Inverse of cell_index.
--
-- > index_to_cell (80,347) == (Column_Ref "CC",348)
-- > index_to_cell (4,5) == (Column_Ref "E",6)
index_to_cell :: (Int,Int) -> Cell_Ref
index_to_cell :: (Row_Ref, Row_Ref) -> Cell_Ref
index_to_cell (Row_Ref
c,Row_Ref
r) = (Row_Ref -> Column_Ref
column_ref Row_Ref
c,Row_Ref
r forall a. Num a => a -> a -> a
+ Row_Ref
1)

-- | 'cell_index' of 'parse_cell_ref_err'
parse_cell_index :: String -> (Int,Int)
parse_cell_index :: String -> (Row_Ref, Row_Ref)
parse_cell_index = Cell_Ref -> (Row_Ref, Row_Ref)
cell_index forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Cell_Ref
parse_cell_ref_err

-- | Type specialised 'Data.Ix.range', cells are in column-order.
--
-- > cell_range (("AA",1),("AC",1)) == [("AA",1),("AB",1),("AC",1)]
--
-- > let r = [("AA",1),("AA",2),("AB",1),("AB",2),("AC",1),("AC",2)]
-- > cell_range (("AA",1),("AC",2)) == r
--
-- > Data.Ix.range (('A',1),('C',1)) == [('A',1),('B',1),('C',1)]
--
-- > let r = [('A',1),('A',2),('B',1),('B',2),('C',1),('C',2)]
-- > Data.Ix.range (('A',1),('C',2)) == r
cell_range :: Cell_Range -> [Cell_Ref]
cell_range :: Cell_Range -> [Cell_Ref]
cell_range ((Column_Ref
c1,Row_Ref
r1),(Column_Ref
c2,Row_Ref
r2)) =
    [(Column_Ref
c,Row_Ref
r) |
     Column_Ref
c <- (Column_Ref, Column_Ref) -> [Column_Ref]
column_range (Column_Ref
c1,Column_Ref
c2)
    ,Row_Ref
r <- (Row_Ref, Row_Ref) -> [Row_Ref]
row_range (Row_Ref
r1,Row_Ref
r2)]

-- | Variant of 'cell_range' in row-order.
--
-- > let r = [("AA",1),("AB",1),("AC",1),("AA",2),("AB",2),("AC",2)]
-- > cell_range_row_order (("AA",1),("AC",2)) == r
cell_range_row_order ::  Cell_Range -> [Cell_Ref]
cell_range_row_order :: Cell_Range -> [Cell_Ref]
cell_range_row_order ((Column_Ref
c1,Row_Ref
r1),(Column_Ref
c2,Row_Ref
r2)) =
    [(Column_Ref
c,Row_Ref
r) |
     Row_Ref
r <- (Row_Ref, Row_Ref) -> [Row_Ref]
row_range (Row_Ref
r1,Row_Ref
r2)
    ,Column_Ref
c <- (Column_Ref, Column_Ref) -> [Column_Ref]
column_range (Column_Ref
c1,Column_Ref
c2)]