{-# LANGUAGE FlexibleInstances, CPP #-}

{-|
Module      : SymmetryOperationsSymbols
Copyright   : (c) Jun Narumi, 2018
License     : BSD-3
Maintainer  : narumij@gmail.com
Stability   : experimental
Portability : ?

Haskell Derivation of symbols and coordinate triplets Library

[References]

1. W. Fischer. and E. Koch. (2006), Derivation of symbols and coordinate triplets International Tables for Crystallography (2006). Vol. A, Chapter 11.2, pp. 812–816.

2. Wondratschek, H. & Neubu ̈ser, J. (1967). Determination of the symmetry elements of a space group from the ‘general positions’ listed in International Tables for X-ray Crystallography, Vol. I. Acta Cryst. 23, 349–352.

-}

module Data.Matrix.SymmetryOperationsSymbols (
  fromMatrix,
  fromMatrix',
  toMatrix,
  toMatrixHex,
  notHexagonal,
  hexagonal
  ) where

import Data.Ratio (Ratio)
import Data.Matrix (Matrix,detLU,trace,identity)
import Text.ParserCombinators.Parsec (ParseError,parse)

import Data.Matrix.SymmetryOperationsSymbols.Common

import Data.Matrix.SymmetryOperationsSymbols.UnitMatrixCase
import Data.Matrix.SymmetryOperationsSymbols.GlideOrReflectionCase
import Data.Matrix.SymmetryOperationsSymbols.RotationCase
import Data.Matrix.SymmetryOperationsSymbols.RotInversionCase

import Data.Matrix.SymmetryOperationsSymbols.Parser
import Data.Matrix.SymmetryOperationsSymbols.SymmetryOperation -- (SymmetryOperation)
import Data.Matrix.SymmetryOperationsSymbols.Calc


-- for doctest
import Data.Matrix.AsXYZ

import Control.Monad.Fail (MonadFail)

#if MIN_VERSION_base(4,11,0)
import qualified Control.Monad.Fail as Fail
#endif

#if MIN_VERSION_base(4,11,0)
instance Fail.MonadFail (Either String) where
  fail = Left
#endif

-- | Derivation of geometric representation of symmetry operations from given matrix of symmetry operations
--
-- jpn) 与えられた対称操作の行列から、対称操作の幾何的表現を導出
--
-- >>> fromMatrix . fromXYZ $ "x,y,z"
-- Right " 1 "
--
-- >>> fromMatrix . fromXYZ $ "-y,x,-z"
-- Right "-4- 0,0,z; 0,0,0"
--
fromMatrix :: Integral a =>
              Matrix (Ratio a) -- ^ 3x4 or 4x4 Matrix
           -> Either String String
fromMatrix = fromMatrix'

-- | Derivation of geometric representation of symmetry operations from given matrix of symmetry operations
--
-- jpn) 与えられた対称操作の行列から、対称操作の幾何的表現を導出
--
fromMatrix' :: (Monad m, MonadFail m, Integral a) => Matrix (Ratio a) -> m String
fromMatrix' m = showSymmetryOperation <$> fromMatrix'' m

-- | Derivation of geometric representation of symmetry operations from given matrix of symmetry operations
--
-- jpn) 与えられた対称操作の行列から、対称操作の幾何的表現を導出
--
fromMatrix'' :: (Monad m, MonadFail m, Integral a) => Matrix (Ratio a) -> m (SymmetryOperation a)
fromMatrix'' m
  -- (i)
  | rotPart m == identity 3             = unitMatrixCase m
  -- (ii) (a)
  | correpondToRotInversion tr det      = rotInversionCase m
  -- -- (ii) (b)
  | correpondToNFoldRotation tr det     = nFoldRotationCase m
  -- -- (ii) (c)
  | correpondToGlideOrReflection tr det = glideOrReflectionCase m
  -- --
  | otherwise = fail "matrix is not symmetry operation."
  where
  tr  = trace (rotPart m)
  det = detLU (rotPart m)

  -- | Derivation of matrix representation from a string of geometric representations of symmetric operations
-- for cubic, tetragonal, orthorhombic, monoclinic, triclinic or rhombohedral.
--
-- jpn) 対称操作の幾何的表現の文字列から行列表現の導出
--
-- >>> prettyXYZ <$> toMatrixHex "-4- 0,0,z; 0,0,0"
-- Right "-y,x,-z"
--
toMatrix :: Integral a =>
            String -- ^ like " -1 0,0,0"
         -> Either ParseError (Matrix (Ratio a)) -- ^ 3x4 Matrix
toMatrix st = parse notHexagonal st st

-- | Derivation of matrix representation from a string of geometric representations of symmetric operations
-- for hexagonal.
--
-- jpn) 対称操作の幾何的表現の文字列から行列表現の導出(六方晶用)
--
-- >>> prettyXYZ <$> toMatrixHex "-3+ 0,0,z; 0,0,0"
-- Right "y,y-x,-z"
--
toMatrixHex :: Integral a =>
               String -- ^ like " -1 0,0,0"
            -> Either ParseError (Matrix (Ratio a)) -- ^ 3x4 Matrix
toMatrixHex st = parse hexagonal st st