{-# LANGUAGE FlexibleInstances #-}

-- |
-- Module    : Data.Kanji.Types
-- Copyright : (c) Colin Woodbury, 2015, 2016
-- License   : GPL3
-- Maintainer: Colin Woodbury <colingw@gmail.com>
--
-- Types for this library. Note that typeclass instances for `ByteString`s
-- are not provided, as `SB.pack` garbles characters above 0xFF.

module Data.Kanji.Types where

import           Data.Char (ord)
import           Data.Kanji.Types.Internal ()
import           Data.Maybe (fromJust)
import qualified Data.Set as S
import qualified Data.Text as ST
import qualified Data.Text.Lazy as LT
import           Lens.Micro

---

-- | Anything that can be transformed into a list of Kanji.
class AsKanji a where

  -- | Traverse into this type to find 0 or more Kanji.
  --
  -- Despite what the Haddock documentation says, this is part of the
  -- minimal complete definition.
  _Kanji :: Traversal' a Kanji

  -- | Transform this string type into a list of Kanji. The source string
  -- and the resulting list might not have the same length, if there
  -- were `Char` in the source that did not fall within the legal
  -- UTF8 range for Kanji.
  asKanji :: a -> [Kanji]
  asKanji a = a ^.. _Kanji

instance AsKanji Char where
  _Kanji f c = if isKanji c then _kanji <$> f (Kanji c) else pure c
  {-# INLINE _Kanji #-}

instance AsKanji [Char] where
  _Kanji = traverse . _Kanji
  {-# INLINE _Kanji #-}

instance AsKanji ST.Text where
  _Kanji = each . _Kanji
  {-# INLINE _Kanji #-}

instance AsKanji LT.Text where
  _Kanji = each . _Kanji
  {-# INLINE _Kanji #-}

-- | A single symbol of Kanji. Japanese Kanji were borrowed from China
-- over several waves during the past millenium. Japan names 2136 of
-- these as their standard set, with rarer characters being the domain
-- of academia and esoteric writers.
--
-- Japanese has several Japan-only Kanji, including:
--
-- * 畑 (a type of rice field)
-- * 峠 (a narrow mountain pass)
-- * 働 (to do physical labour)
newtype Kanji = Kanji { _kanji :: Char } deriving (Eq, Ord, Show)

-- | A Level or "Kyuu" (級) of Japanese Kanji ranking. There are 12 of these,
-- from 10 to 1, including intermediate levels between 3 and 2, and 2 and 1.
--
-- Japanese students will typically have Level-5 ability by the time they
-- finish elementary school. Level-5 accounts for 1006 characters.
--
-- By the end of middle school, they would have covered up to Level-3
-- (1607 Kanji) in their Japanese class curriculum.
--
-- While Level-2 (2136 Kanji) is considered "standard adult" ability,
-- many adults could not pass the Level-2, or even the Level-Pre2 (1940 Kanji)
-- exam without considerable study.
--
-- Level data for Kanji above Level-2 is currently not provided by
-- this library.
data Level = Level { _allKanji :: S.Set Kanji
                   , _rank :: Rank
                   } deriving (Eq, Show)

-- | A numeric representation of a `Level`.
data Rank = Ten | Nine | Eight | Seven | Six | Five | Four | Three | PreTwo
  | Two | PreOne | One deriving (Eq, Ord, Enum, Read, Show)

-- | Discover a Rank's numeric representation, as a `Float`.
fromRank :: Rank -> Float
fromRank = fromJust . flip lookup rankMap

-- | A mapping of Ranks to their numeric representation.
rankMap :: [(Rank,Float)]
rankMap = zip [Ten ..] [10,9,8,7,6,5,4,3,2.5,2,1.5,1]

-- | Legal Kanji appear between UTF8 characters 19968 and 40959.
isKanji :: Char -> Bool
isKanji c = lowLimit <= c' && c' <= highLimit
    where c' = ord c
          lowLimit  = 19968  -- This is `一`
          highLimit = 40959  -- I don't have the right fonts to display this.