module Wordlint.Wordpairs where
import  Data.List 
import Wordlint.Words

--
-- This module contains types and functions for working with pairs of matching
-- words and the distances between them. The key type is a Wordpair, which
-- contains two Word elements and the difference between their Positions.
--

data Wordpair a = Wordpair 
                {wone  :: Word a
                ,wtwo  :: Word a
                ,pdiff :: a 
                } 

type Wordpairs a = [Wordpair a]

-- Wordpair equality based on coordinates so that
-- union of multiple checks can be found regardless
--
instance Eq (Wordpair a) where
         x == y = getWordpairCoords x == getWordpairCoords y
-----------------------------------------------------------------
--
-- Creating and filtering Wordpairs
--
-----------------------------------------------------------------
makeWordpairs :: (Num a, NumOps a) => Word a -> Word a -> Wordpair a
makeWordpairs wx@(Word _ x _ _) wy@(Word _ y _ _) = Wordpair wx wy (y-x)

-- Convert a list of matching (but separately-located) Words into a list of
-- Wordpair elements. This counts by two
sortWordsByString :: (Num a, NumOps a) =>  Words a -> Wordpairs a
sortWordsByString [] = []
sortWordsByString [_] = []
sortWordsByString [x,xs] =  [makeWordpairs x xs | x `checkWordEquality` xs] 
sortWordsByString ( x:y:xs ) = if x `checkWordEquality` y
                               then makeWordpairs x y : sortWordsByString (y:xs)
                               else sortWordsByString (y:xs)

filterWordpairsByDistance :: (Num a, Eq a, Ord a, NumOps a) => Wordpairs a -> a -> Wordpairs a
filterWordpairsByDistance [] _ = []

filterWordpairsByDistance (x:xs) i = if pdiff x <= i
                               then x : filterWordpairsByDistance xs i
                               else filterWordpairsByDistance xs i

-----------------------------------------------------------------
--
-- Sorting wordpairs
--
-----------------------------------------------------------------

sortWordPairsByPosition :: (Num a, Ord a, NumOps a) => Wordpairs a -> Wordpairs a
sortWordPairsByPosition [] = []
sortWordPairsByPosition [_] = []
sortWordPairsByPosition xs = sortBy positionsort xs
  where positionsort (Wordpair (Word _ x _ _) _ _ ) (Wordpair (Word _ y _ _) _ _) 
                | x < y = LT
                | x > y = GT
                | x == y = EQ
        positionsort Wordpair{} Wordpair{} = EQ

sortWordPairsByDistance :: (Num a, Ord a, NumOps a) => Wordpairs a -> Wordpairs a
sortWordPairsByDistance [] = []
sortWordPairsByDistance [_] = []
sortWordPairsByDistance xs = sortBy positionsort xs
  where positionsort (Wordpair _ _ x ) (Wordpair _ _ y ) 
                | x < y = LT
                | x > y = GT
                | x == y = EQ
        positionsort Wordpair{} Wordpair{} = EQ

-----------------------------------------------------------------
--
-- Functions to extract data from Wordpairs for easier printing
--
-----------------------------------------------------------------

getWordPairString :: Wordpair a -> String
getWordPairString wp = if wordone == wordtwo
                        then wordone
                        else
                        "Error with word pair"
  where 
    wordone = lemma $ wone wp
    wordtwo = lemma $ wtwo wp

getWordpairPositions :: (NumOps a) => Wordpair a -> (a,a)
getWordpairPositions wp = (position $ wone wp,position $ wtwo wp)

getWordpairLines :: (NumOps a) => Wordpair a -> (Int,Int)
getWordpairLines wp = (line $ wone wp,line $ wtwo wp)


-- return ((Line,Col)(Line,Col))
getWordpairCoords :: Wordpair a -> ((Int,Int),(Int,Int))
getWordpairCoords wp = ((line firstword,column firstword),(line secondword,column secondword))
    where
      firstword = wone wp
      secondword = wtwo wp

showFirstWordpairCoords :: (Show a) => Wordpair a -> String
showFirstWordpairCoords x = lin ++ "," ++ col
  where lin = show $ line wor
        col = show $ column wor
        wor = wone x

showSecondWordpairCoords :: (Show a) => Wordpair a -> String
showSecondWordpairCoords x = lin ++ "," ++ col
  where lin = show $ line wor
        col = show $ column wor
        wor = wtwo x