# encoding: ascii
# api: powershell
# title: Flatten hashtable
# description: Flattens a hashtable, removing ‘unnecessary’ levels of nesting.
# version: 0.1
# type: script
# author: Ross J Micheals
# license: CC0
# function: ConvertTo-FlatterHashtable
# x-poshcode-id: 5573
# x-archived: 2014-11-17T22:49:56
# x-published: 2014-11-06T16:20:00
#
#
<#

.SYNOPSIS
    Flattens a hashtable, removing 'unnecessary' levels of nesting.


.DESCRIPTION

    This command takes as input, a (Powershell) hashtable and outputs a new hashtable
    in which 'unnecessary' levels of nesting are removed. A hashtable contains an 'unnecessary' level 
    of nesting if that hashtable either *is* or *contains* a hashtable with a single key-value pair 
    and that value is also a hashtable.
    
    The command is run in either 'parent biased' or 'child biased' mode. In 'parent biased' mode,
    the command will preserve the key of the parent-most level of a flattened hashtable. In 'child
    biased' mode, the command will preserve the key of the child-most level of a flattened hashtable.
    
    DETAILED EXAMPLE
    
    Consider the hashtable @{x=@{y=@{z=1}}}. This hashtable contains a doubly nested hashtable.
    The outer hashtable contributes to an unnecessary level of nesting because it has a single (key, value) 
    pair (x, {y=@{z=1}}) where the value, {y=@{z=1}}, is also a hashtable. The nested hashtable {y=@{z=1}} 
    similarly contributes 'unnecessary' nesting. The innermost hashtable @{z=1} does not contribute 
    to 'unnecessary' nesting; it does not contain another hashtable.
       
    In 'parent biased' mode, @{x=@{y=@{z=1}}} flattens to @{x=1}. In 'child biased' mode, it flattens 
    to @{z=1}.


.PARAMETER Source

    Required. The hashtable to be flattened.


.PARAMETER ChildBiased

    Optional. Flattens the source hashtable in 'child biased' mode. If this switch is absent, then then
    command defaults to 'parent biased' mode.

.EXAMPLE

    Flatten a nested hashtable using the default ('parent biased') mode.

    PS C:\> @{a=@{b=1}} | ConvertTo-FlatterHashtable

    Name                           Value                                                                                                
    ----                           -----                                                                                                
    a                              1  


.EXAMPLE

    Flatten a nested hashtable using 'child biased' mode.

    PS C:\> ConvertTo-FlatterHashtable -Source @{a=@{b=@{c=1}}} -ChildBiased

    Name                           Value                                                                                                
    ----                           -----                                                                                                
    c                              1  
    
    
    
#>

function ConvertTo-FlatterHashtable {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelinebyPropertyName=$True)] [Hashtable] $Source, 
        [Switch] $ChildBiased
    )
    
    BEGIN {}
 
    PROCESS {

        function ConvertTo-ChildBiasedFlatterHashtable([hashtable] $Source) {
            $ht = @{}
        
            foreach ($key in $Source.Keys) {
                $value = $Source[$key]
                if ($value -and $value.Count -eq 1 -and $value -as [Hashtable]) {
                    $ht = ConvertTo-ChildBiasedFlatterHashtable $value
                } else {
                    $ht[$key] = $value
                }
            }
            $ht
        } 

        function ConvertTo-ParentBiasedFlatterHashtable([hashtable] $Source) {
    
            function FlattenHashtable($start) {
                if ($start -and $start -as [Hashtable] -and $start.Count -eq 1) {
                    FlattenHashtable $start[[string]($start.Keys[0])]
                } else {
                    $start
                }
            }

            $ht = @{}
            foreach ($key in $Source.Keys) {
                $ht[$key] =  FlattenHashtable $Source[$key]
            }
            $ht
        }

        if ($ChildBiased) {
            ConvertTo-ChildBiasedFlatterHashtable $Source
        } else {
            ConvertTo-ParentBiasedFlatterHashtable $Source
        }
    }

    END {}
    
}
