module BioInf.RNAdesign.Graph where

import Control.Arrow (first,second)
import Data.Graph.Inductive.Basic
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Data.Graph.Inductive.Query
import Data.List (nub,partition)

import Biobase.Secondary.Diagrams



-- | Given the one to many structures, create the independent graphs, where
-- each graph describes a set of dependent edges in the basepairing.

independentGraphs xs
  | null xs = error "You should give at least one structure. If you did, you have found a bug, yeah!"
  | any ((/=lx).length) xs = error $ "At least one structure with different length was found" ++ show xs
  | otherwise = independentComponents g
  where
    lx = length $ head xs
    g = mkUnionGraph xs

-- | Union of several graphs, created from secondary structure.

mkUnionGraph = unions . map (pairlistToGraph . (mkD1S :: String -> D1Secondary))

-- | Given k graphs, each with nodes [1..n], provide the union of all edges.

unions :: Eq b => [Gr a b] -> Gr a b
unions [] = empty
unions xs@(x:_) = mkGraph (labNodes x) (nub $ concatMap labEdges xs) where

-- | Given a pairlist, generate the secondary structure graph.

pairlistToGraph :: D1Secondary -> Gr () ()
pairlistToGraph d =
  let (len, ps) = fromD1S d
  in  undir $ mkUGraph [0..len -1] ps

-- | Split the graph into (simple, complex) components. The simple components
-- can trivially be filled with any pair. The complex components require an Ear
-- or Woffle decomposition. Simple components are acyclic.

independentComponents :: DynGraph gr => gr () () -> [gr () ()]
independentComponents g = map f $ components g where
  f ns = mkUGraph ns (edges g)

-- | Tests if the given graph is bipartite, which is true if the even/odd BST
-- trees contain no edges

isBipartite :: DynGraph gr => gr a b -> Bool
isBipartite g =  e && o where
  -- True, if there are no edges
  (e,o) = both (null . edges) $ f g
  -- generate the (even,odd) distance graphs
  f g = both (flip delNodes g . map fst) . partition (even . snd) $ level (fst $ head $ labNodes g) g
  both f = second f . first f