joinRTuples :: RTuple -> RTuple -> RTuple
joinRTuples tleft tright = 
    let
        -- change keys in tright what needs to be renamed because also appear in tleft
        -- first keep a copy of the tright pairs that dont need a key change
        dontNeedChange  = HM.difference tright tleft
        changedPart = changeKeys tleft tright
        -- create  a new version of tright, with no common keys with tleft
        new_tright = HM.union dontNeedChange changedPart
    in HM.union tleft new_tright  
        where 
            -- rename keys of right rtuple until there no more common keys with the left rtuple            
            changeKeys :: RTuple -> RTuple -> RTuple
            changeKeys tleft changedPart = 
                if isRTupEmpty (HM.intersection changedPart tleft)
                    then -- we are done, no more common keys
                        changedPart
                    else
                        -- there are still common keys to change
                        let
                            needChange = HM.intersection changedPart tleft -- (k,v) pairs that exist in changedPart and the keys also appear in tleft. Thus these keys have to be renamed
                            dontNeedChange  = HM.difference changedPart tleft -- (k,v) pairs that exist in changedPart and the keys dont appear in tleft. Thus these keys DONT have to be renamed
                            new_changedPart =  fromList $ Data.List.map (\(k,v) -> (newKey k, v)) $ toList needChange
                        in HM.union dontNeedChange (changeKeys tleft new_changedPart)
                          
            -- generate a new key as this:
            -- "hello" -> "hello_1"
            -- "hello_1" -> "hello_2"
            -- "hello_2" -> "hello_3"
            newKey :: ColumnName -> ColumnName
            newKey name  = 
                let 
                    lastChar = Data.List.last name
                    beforeLastChar = name !! (Data.List.length name - 2)
                in  
                    if beforeLastChar == '_'  &&  Data.Char.isDigit lastChar
                                    then (Data.List.take (Data.List.length name - 2) name) ++ ( '_' : (show $ (read (lastChar : "") :: Int) + 1) )
                                    else name ++ "_1"


-- | RTable Left Outer Join Operator
joinRTuples :: RTuple -> RTuple -> RTuple
joinRTuples tleft tright = 
    let
        -- change keys in tright what needs to be renamed because also appear in tleft
        -- first keep a copy of the tright pairs that dont need a key change
        dontNeedChange  = HM.difference tright tleft
        changedPart = changeKeys tleft tright
        -- create  a new version of tright, with no common keys with tleft
        new_tright = HM.union dontNeedChange changedPart
    in HM.union tleft new_tright  
        where 
            -- rename keys of right rtuple until there no more common keys with the left rtuple            
            changeKeys :: RTuple -> RTuple -> RTuple
            changeKeys tleft changedPart = 
                if isRTupEmpty (HM.intersection changedPart tleft)
                    then -- we are done, no more common keys
                        changedPart
                    else
                        -- there are still common keys to change
                        let
                            needChange = HM.intersection changedPart tleft -- (k,v) pairs that exist in changedPart and the keys also appear in tleft. Thus these keys have to be renamed
                            dontNeedChange  = HM.difference changedPart tleft -- (k,v) pairs that exist in changedPart and the keys dont appear in tleft. Thus these keys DONT have to be renamed
                            new_changedPart =  fromList $ Data.List.map (\(k,v) -> (newKey k, v)) $ toList needChange
                        in HM.union dontNeedChange (changeKeys tleft new_changedPart)
                          
            -- generate a new key as this:
            -- "hello" -> "hello_1"
            -- "hello_1" -> "hello_2"
            -- "hello_2" -> "hello_3"
            newKey :: ColumnName -> ColumnName
            newKey name  = 
                let 
                    lastChar = Data.List.last name
                    beforeLastChar = name !! (Data.List.length name - 2)
                in  
                    if beforeLastChar == '_'  &&  Data.Char.isDigit lastChar
                                    then (Data.List.take (Data.List.length name - 2) name) ++ ( '_' : (show $ (read (lastChar : "") :: Int) + 1) )
                                    else name ++ "_1"


-- | RTable Left Outer Join Operator
joinRTuples tleft tright = 
    let
        -- change keys in tright what needs to be renamed because also appear in tleft
        -- first keep a copy of the tright pairs that dont need a key change
        dontNeedChange  = HM.difference tright tleft
        changedPart = changeKeys tleft tright
        -- create  a new version of tright, with no common keys with tleft
        new_tright = HM.union dontNeedChange changedPart
    in HM.union tleft new_tright  
        where 
            -- rename keys of right rtuple until there no more common keys with the left rtuple            
            changeKeys :: RTuple -> RTuple -> RTuple
            changeKeys tleft changedPart = 
                if isRTupEmpty (HM.intersection changedPart tleft)
                    then -- we are done, no more common keys
                        changedPart
                    else
                        -- there are still common keys to change
                        let
                            needChange = HM.intersection changedPart tleft -- (k,v) pairs that exist in changedPart and the keys also appear in tleft. Thus these keys have to be renamed
                            dontNeedChange  = HM.difference changedPart tleft -- (k,v) pairs that exist in changedPart and the keys dont appear in tleft. Thus these keys DONT have to be renamed
                            new_changedPart =  fromList $ Data.List.map (\(k,v) -> (newKey k, v)) $ toList needChange
                        in HM.union dontNeedChange (changeKeys tleft new_changedPart)
                          
            -- generate a new key as this:
            -- "hello" -> "hello_1"
            -- "hello_1" -> "hello_2"
            -- "hello_2" -> "hello_3"
            newKey :: ColumnName -> ColumnName
            newKey name  = 
                let 
                    lastChar = Data.List.last name
                    beforeLastChar = name !! (Data.List.length name - 2)
                in  
                    if beforeLastChar == '_'  &&  Data.Char.isDigit lastChar
                                    then (Data.List.take (Data.List.length name - 2) name) ++ ( '_' : (show $ (read (lastChar : "") :: Int) + 1) )
                                    else name ++ "_1"


-- | RTable Left Outer Join Operator