{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE ViewPatterns #-}

-- For debug

module PrettyPrint
    ( printBin
    , showBin
    , printJavaClass
    , showJavaClass
    ) where

import JavaClass

import Data.Array
import qualified Data.ByteString as B
import Numeric

printBin :: B.ByteString -> IO ()
printBin = putStrLn . showBin

showBin :: B.ByteString -> String
showBin (B.uncons -> Just (x, xs)) = add0 . showHex x . (' ' :) . showBin $ xs
showBin _ = ""

add0 :: String -> String
add0 xs@(_ : ' ' : _) = '0' : xs
add0 xs = xs

printJavaClass :: JavaClass -> IO ()
printJavaClass = putStrLn . showJavaClass

showJavaClass :: JavaClass -> String
showJavaClass (JavaClass v cp fs this super i f m a) = unlines
    [ "version: " ++ showVersion 0 v
    , "constant pool:"
    , showConstPool 1 cp
    , "access flags:"
    , showFlags 1 fs
    , "this class: " ++ show this
    , "super class: " ++ show super
    , "interfaces: " ++ show i
    , "fields: "
    , showFields 1 f
    , "methods: "
    , showMethods 1 m
    , "attributes: "
    , showAttributes 1 a
    ]

showVersion :: Int -> Version -> String
showVersion n = app <$> (show . majorVersion) <*> (show . minorVersion)
    where
        app x y = indent n ++ x ++ "." ++ y

showConstPool :: Int -> Array Int CpInfo -> String
showConstPool n = unlines . map f . assocs
    where
        f (i, e) = indent n ++ show i ++ ": " ++ show e

showFlags :: Int -> [AccessFlag] -> String
showFlags n = (indent n ++) . foldr f ""
    where
        f x acc = show x ++ ' ' : acc

showFields :: Int -> [FieldInfo] -> String
showFields n = unlines . map f
    where
        f = ("field:\n" ++) . showFieldInfo (n + 1)

showFieldInfo :: Int -> FieldInfo -> String
showFieldInfo n (FieldInfo fs name desc attrs) = unlines . map (indent n ++) $
    [ "access flags: "
    , showFlags 1 fs
    , "name: " ++ show name
    , "descriptor: " ++ show desc
    , "attributes:"
    , showAttributes 1 attrs]

showMethods :: Int -> [MethodInfo] -> String
showMethods n = unlines . map f
    where
        f = ("method:\n" ++) . showMethodInfo (n + 1)

showMethodInfo :: Int -> MethodInfo -> String
showMethodInfo n (MethodInfo fs name desc attrs) = unlines . map (indent n ++) $
    [ "access flags: "
    , showFlags 1 fs
    , "name: " ++ show name
    , "descriptor: " ++ show desc
    , "attributes:"
    , showAttributes 1 attrs]


showAttributes :: Int -> [AttributeInfo] -> String
showAttributes n = unlines . map f
    where
        f = (indent n ++) . show -- showAttributeInfo (n + 1)

indent :: Int -> String
indent = flip replicate '\t'
