typeLinkingCheck db imps (ENV su c) = if (elem Nothing imps') || (null cts') then [] else tps
    where
        (SU cname kd st inhf) = su
        (SU cnamei kdi sti inhfi) = inhf
        [sym] = [sym | sym <- symbolTable inhf, localName sym == last cname]
        SYM mds ls ln lt = sym
        
        imps' = map (traverseNodeEntry db) imps
        
        cts = map (\env -> typeLinkingCheck db imps env) c
        cts' = if and $ map (\tps -> tps /= []) cts then [TypeVoid] else []
        --cts' = if or $ map null cts then [] else [TypeVoid]
        
        [varsym] = st
        tps = case kd of
                Var expr -> if typeLinkingExpr db imps su (Binary "=" (ID (Name ([localName varsym])) 0) expr 0) == [] then [] else cts'

                Field varsym (Just expr) -> let syms = dropWhile (varsym /=) [sym | sym@(SYM mds _ _ _) <- sti, not $ elem "static" mds]
                                                forward = or (map (\sym -> identifierInExpr (localName sym) expr) syms)
                                            in if forward
                                                then typeLinkingFailure $ "forward use of syms " ++ (show varsym) ++ (show expr)
                                                else if typeLinkingExpr db imps su (Binary "=" (ID (Name ([localName varsym])) 0) expr 0) == [] then typeLinkingFailure $ "field type mis match expression " ++ (show varsym) ++ (show expr) else cts'
                Field _ Nothing -> cts'                                                
                Exp expr -> typeLinkingExpr db imps su expr
                
                Ret expr -> let rtp = scopeReturnType su in
                            let incons = scopeConstructor su in
                            case (rtp, isNothing expr) of
                                (TypeVoid, True) -> [TypeVoid]
                                (TypeVoid, False) -> typeLinkingFailure $ "Return in a void method: " ++ (show expr) 
                                (_, True) -> if incons then [TypeVoid] else typeLinkingFailure $ "Return nothing in a non-void method: " ++ (show expr)
                                _ -> case filter filterNonFunction $ typeLinkingExpr db imps su (fromJust expr) of
                                        [] -> typeLinkingFailure $ "Return type no match: " ++ (show expr)
                                        [tp] -> if not . null $ assignConversion db tp rtp then [TypeVoid] else typeLinkingFailure $ "Return assign conversion failure: " ++ (show tp) ++ (show rtp)
                                        a -> typeLinkingFailure $ "Return type multi match: " ++ (show expr) ++ (show a)

                ForBlock -> let typeCond = cts !! 1
                                casting = castConversion db (head typeCond) TypeBoolean in
                            case (typeCond, casting) of
                                ([], _) -> typeLinkingFailure $ "For condition: " ++ (show typeCond)
                                ([TypeVoid], _) -> cts'
                                ([TypeBoolean], _) -> cts'
                                (_, []) -> typeLinkingFailure $ "For condition: " ++ (show typeCond)
                                (_, _) -> cts'

                WhileBlock expr -> let typeExpr = typeLinkingExpr db imps su expr
                                       condition = (not . null $ typeExpr) && (length typeExpr == 1) && (not . null $ castConversion db (head typeExpr) TypeBoolean) in
                                    if condition then cts' else typeLinkingFailure $ "While condition: " ++ (show typeExpr)

                IfBlock expr -> let typeExpr = typeLinkingExpr db imps su expr
                                    condition = (not . null $ typeExpr) && (length typeExpr == 1) && (not . null $ castConversion db (head typeExpr) TypeBoolean) in
                                    if condition then cts' else typeLinkingFailure $ "If condition: " ++ (show typeExpr) ++ (show expr)

                Class -> cts'
                Method _ -> cts'
                Interface -> cts'
                Statement -> cts'
                Package -> cts'

{-
typeLinkingPrefix :: TypeNode -> [[String]] -> [String] -> [[String]]
typeLinkingPrefix db imps cname = concat tps
    where
        ps = map (\i -> (take i cname)) [1..(length $ init cname)]
        tps = map (traverseTypeEntryWithImports db imps) ps
-}
typeLinkingCheck db imps (ENV su c) = if (elem Nothing imps') || (null cts') then [] else tps
    where
        (SU cname kd st inhf) = su
        (SU cnamei kdi sti inhfi) = inhf
        [sym] = [sym | sym <- symbolTable inhf, localName sym == last cname]
        SYM mds ls ln lt = sym
        
        imps' = map (traverseNodeEntry db) imps
        
        cts = map (\env -> typeLinkingCheck db imps env) c
        cts' = if and $ map (\tps -> tps /= []) cts then [TypeVoid] else []
        --cts' = if or $ map null cts then [] else [TypeVoid]
        
        [varsym] = st
        tps = case kd of
                Var expr -> if typeLinkingExpr db imps su (Binary "=" (ID (Name ([localName varsym])) 0) expr 0) == [] then [] else cts'

                Field varsym (Just expr) -> let syms = dropWhile (varsym /=) [sym | sym@(SYM mds _ _ _) <- sti, not $ elem "static" mds]
                                                forward = or (map (\sym -> identifierInExpr (localName sym) expr) syms)
                                            in if forward
                                                then typeLinkingFailure $ "forward use of syms " ++ (show varsym) ++ (show expr)
                                                else if typeLinkingExpr db imps su (Binary "=" (ID (Name ([localName varsym])) 0) expr 0) == [] then typeLinkingFailure $ "field type mis match expression " ++ (show varsym) ++ (show expr) else cts'
                Field _ Nothing -> cts'                                                
                Exp expr -> typeLinkingExpr db imps su expr
                
                Ret expr -> let rtp = scopeReturnType su in
                            let incons = scopeConstructor su in
                            case (rtp, isNothing expr) of
                                (TypeVoid, True) -> [TypeVoid]
                                (TypeVoid, False) -> typeLinkingFailure $ "Return in a void method: " ++ (show expr) 
                                (_, True) -> if incons then [TypeVoid] else typeLinkingFailure $ "Return nothing in a non-void method: " ++ (show expr)
                                _ -> case filter filterNonFunction $ typeLinkingExpr db imps su (fromJust expr) of
                                        [] -> typeLinkingFailure $ "Return type no match: " ++ (show expr)
                                        [tp] -> if not . null $ assignConversion db tp rtp then [TypeVoid] else typeLinkingFailure $ "Return assign conversion failure: " ++ (show tp) ++ (show rtp)
                                        a -> typeLinkingFailure $ "Return type multi match: " ++ (show expr) ++ (show a)

                ForBlock -> let typeCond = cts !! 1
                                casting = castConversion db (head typeCond) TypeBoolean in
                            case (typeCond, casting) of
                                ([], _) -> typeLinkingFailure $ "For condition: " ++ (show typeCond)
                                ([TypeVoid], _) -> cts'
                                ([TypeBoolean], _) -> cts'
                                (_, []) -> typeLinkingFailure $ "For condition: " ++ (show typeCond)
                                (_, _) -> cts'

                WhileBlock expr -> let typeExpr = typeLinkingExpr db imps su expr
                                       condition = (not . null $ typeExpr) && (length typeExpr == 1) && (not . null $ castConversion db (head typeExpr) TypeBoolean) in
                                    if condition then cts' else typeLinkingFailure $ "While condition: " ++ (show typeExpr)

                IfBlock expr -> let typeExpr = typeLinkingExpr db imps su expr
                                    condition = (not . null $ typeExpr) && (length typeExpr == 1) && (not . null $ castConversion db (head typeExpr) TypeBoolean) in
                                    if condition then cts' else typeLinkingFailure $ "If condition: " ++ (show typeExpr) ++ (show expr)

                Class -> cts'
                Method _ -> cts'
                Interface -> cts'
                Statement -> cts'
                Package -> cts'

{-
typeLinkingPrefix :: TypeNode -> [[String]] -> [String] -> [[String]]
typeLinkingPrefix db imps cname = concat tps
    where
        ps = map (\i -> (take i cname)) [1..(length $ init cname)]
        tps = map (traverseTypeEntryWithImports db imps) ps
-}
typeLinkingCheck db imps (ENV su c) = if (elem Nothing imps') || (null cts') then [] else tps
    where
        (SU cname kd st inhf) = su
        (SU cnamei kdi sti inhfi) = inhf
        [sym] = [sym | sym <- symbolTable inhf, localName sym == last cname]
        SYM mds ls ln lt = sym
        
        imps' = map (traverseNodeEntry db) imps
        
        cts = map (\env -> typeLinkingCheck db imps env) c
        cts' = if and $ map (\tps -> tps /= []) cts then [TypeVoid] else []
        --cts' = if or $ map null cts then [] else [TypeVoid]
        
        [varsym] = st
        tps = case kd of
                Var expr -> if typeLinkingExpr db imps su (Binary "=" (ID (Name ([localName varsym])) 0) expr 0) == [] then [] else cts'

                Field varsym (Just expr) -> let syms = dropWhile (varsym /=) [sym | sym@(SYM mds _ _ _) <- sti, not $ elem "static" mds]
                                                forward = or (map (\sym -> identifierInExpr (localName sym) expr) syms)
                                            in if forward
                                                then typeLinkingFailure $ "forward use of syms " ++ (show varsym) ++ (show expr)
                                                else if typeLinkingExpr db imps su (Binary "=" (ID (Name ([localName varsym])) 0) expr 0) == [] then typeLinkingFailure $ "field type mis match expression " ++ (show varsym) ++ (show expr) else cts'
                Field _ Nothing -> cts'                                                
                Exp expr -> typeLinkingExpr db imps su expr
                
                Ret expr -> let rtp = scopeReturnType su in
                            let incons = scopeConstructor su in
                            case (rtp, isNothing expr) of
                                (TypeVoid, True) -> [TypeVoid]
                                (TypeVoid, False) -> typeLinkingFailure $ "Return in a void method: " ++ (show expr) 
                                (_, True) -> if incons then [TypeVoid] else typeLinkingFailure $ "Return nothing in a non-void method: " ++ (show expr)
                                _ -> case filter filterNonFunction $ typeLinkingExpr db imps su (fromJust expr) of
                                        [] -> typeLinkingFailure $ "Return type no match: " ++ (show expr)
                                        [tp] -> if not . null $ assignConversion db tp rtp then [TypeVoid] else typeLinkingFailure $ "Return assign conversion failure: " ++ (show tp) ++ (show rtp)
                                        a -> typeLinkingFailure $ "Return type multi match: " ++ (show expr) ++ (show a)

                ForBlock -> let typeCond = cts !! 1
                                casting = castConversion db (head typeCond) TypeBoolean in
                            case (typeCond, casting) of
                                ([], _) -> typeLinkingFailure $ "For condition: " ++ (show typeCond)
                                ([TypeVoid], _) -> cts'
                                ([TypeBoolean], _) -> cts'
                                (_, []) -> typeLinkingFailure $ "For condition: " ++ (show typeCond)
                                (_, _) -> cts'

                WhileBlock expr -> let typeExpr = typeLinkingExpr db imps su expr
                                       condition = (not . null $ typeExpr) && (length typeExpr == 1) && (not . null $ castConversion db (head typeExpr) TypeBoolean) in
                                    if condition then cts' else typeLinkingFailure $ "While condition: " ++ (show typeExpr)

                IfBlock expr -> let typeExpr = typeLinkingExpr db imps su expr
                                    condition = (not . null $ typeExpr) && (length typeExpr == 1) && (not . null $ castConversion db (head typeExpr) TypeBoolean) in
                                    if condition then cts' else typeLinkingFailure $ "If condition: " ++ (show typeExpr) ++ (show expr)

                Class -> cts'
                Method _ -> cts'
                Interface -> cts'
                Statement -> cts'
                Package -> cts'

{-
typeLinkingPrefix :: TypeNode -> [[String]] -> [String] -> [[String]]
typeLinkingPrefix db imps cname = concat tps
    where
        ps = map (\i -> (take i cname)) [1..(length $ init cname)]
        tps = map (traverseTypeEntryWithImports db imps) ps
-}