Schematics/Gallery/Use-GallerySchematic.ps1

function Use-GallerySchematic
{
    <#
    .Synopsis
        Builds a web application according to a schematic
    .Description
        Use-Schematic builds a web application according to a schematic.
         
        Web applications should not be incredibly unique: they should be built according to simple schematics.
    .Notes
     
        When ConvertTo-ModuleService is run with -UseSchematic, if a directory is found beneath either Pipeworks
        or the published module's Schematics directory with the name Use-Schematic.ps1 and containing a function
        Use-Schematic, then that function will be called in order to generate any pages found in the schematic.
         
        The schematic function should accept a hashtable of parameters, which will come from the appropriately named
        section of the pipeworks manifest
        (for instance, if -UseSchematic Blog was passed, the Blog section of the Pipeworks manifest would be used for the parameters).
         
        It should return a hashtable containing the content of the pages. Content can either be static HTML or .PSPAGE
    #>

    [OutputType([Hashtable])]
    param(
    # Any parameters for the schematic
    [Parameter(Mandatory=$true)]
    [Hashtable]$Parameter,
    
    # The pipeworks manifest, which is used to validate common parameters
    [Parameter(Mandatory=$true)][Hashtable]$Manifest,
    
    # The directory the schemtic is being deployed to
    [Parameter(Mandatory=$true)][string]$DeploymentDirectory,
    
    # The directory the schematic is being deployed from
    [Parameter(Mandatory=$true)][string]$InputDirectory     
    )
    
    process {
    
        if (-not $Parameter.Collection) {
            Write-Error "No collection found in parameters"
            return
        }
        
        
        
        $requiresTableConnection = 
            $parameter.Collection |
                Where-Object { $_.Partition }
        
        
        $localInventory =
            $parameter.Collection |
                Where-Object { $_.Directory } 
        
        if (-not $localInventory) {
            $requiresTableConnection  = $true
        }
        if ($requiresTableConnection ) {
            if (-not $Manifest.Table.Name) {
                Write-Error "No table found in manifest"
                return
            }
            
            if (-not $Manifest.Table.StorageAccountSetting) {
                Write-Error "No storage account name setting found in manifest"
                return
            }
            
            if (-not $manifest.Table.StorageKeySetting) {
                Write-Error "No storage account key setting found in manifest"
                return
            }
        }
        
        $manifest.AcceptAnyUrl = $true
                                        
        
        $anyPage = {
        
        
        
            if ($pipeworksManifest.Table) {
            
                # Pick out the storage account and storage key from the manifest. If they are not present, the values will be blank.
                $storageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting)
                $storageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting)                                                           
            }

            #region Get collection metadata
            $CollectionNames  = @()

            
            $Collections = 
                foreach ($CollectionInfo in $pipeworksManifest.Gallery.Collection) {
                    $Collection = New-Object PSObject -Property $CollectionInfo
                    $CollectionNames += $Collection.Name
                    $Collection 
                }
        
            #endregion Get collection metadata
               
                
            
            # Determine relative URL and original URL
            $originalUrl = $context.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

            $pathInfoUrl = $request.Url.ToString().Substring(0, $request.Url.ToString().LastIndexOf("/"))
            
                
                
            $pathInfoUrl = $pathInfoUrl.ToLower()
            $protocol = ($request['Server_Protocol'].Split("/", [StringSplitOptions]"RemoveEmptyEntries"))[0]  # Split out the protocol
            
            

            $serverName= $request['Server_Name']                     # And what it thinks it called the server
            
            $fullOriginalUrl = $protocol.ToLower() + "://" + $serverName + $request.Params["HTTP_X_ORIGINAL_URL"]
            $fullOriginalUrl = $fullOriginalUrl.ToLower()
            
            $pathInfoUrl = $pathInfoUrl.ToLower()
            $relativeUrl = $fullOriginalUrl.Replace("$pathInfoUrl", "")            
            
            
            if (-not $fullOriginalUrl) {
                "No Original URL"
                return
            }
            
            $pageCss = @{
    "body" = @{
        "line-height" = "160%"
        "padding-top" = "0px"
        "padding-left" = "0px"
        "padding-right" = "0px"
        "padding-bottom" = "0px"
        "margin-top" = "0px"
        "margin-left" = "0px"
        "margin-right" = "0px"
        "margin-bottom" = "0px"
    }
} 
            $ShowThing= {

param([Parameter(Mandatory=$true)][string]$Name,
[string[]]$Caption,
[string[]]$Url,
[string]$FirstColor = "#012456",
[string]$HeaderTextColor = "#fff",
[string]$MainTextColor = "#000000",
[string]$SecondColor = "#010c1d",
[string]$ThirdColor = "#ffffff",
[string]$Thing)
"<h1 style='top:25px;font-variant:normal;font-weight:bold;font-size:24px;margin-bottom:5px;line-height:2em'>$Name</h1>" | 
    New-Region -LayerID MainHeaderContainer -Style @{
        "color" = "$HeaderTextColor"
        "letter-spacing" = "-1px"
        "margin-left" = "17%"
        "padding-right" = "40px"
        "padding-left" = "40px"
        "padding-bottom" = "0px"
        "padding-top" = "0px"
        "min-width" = "480px"
        "max-width" = "960px"
        #"text-shadow" ="0 2px 0 #510000"
    } |
    New-Region -LayerID PageHeader -Style @{
        width = "100%"
        "height" = "80px"
        "background-image" = "none"
        "background-attachment" = "scroll"
        "background-repeat" = "repeat"        
        "background-position-x" = "0%"
        "background-position-y" = "0%"
        "background-origin" = "padding-box"
        "background-clip" = "border-box"
        "background-size" = "auto"
        "background-color" = "$FirstColor"
        "text-align" = "left"
        
    }
    
$count=  0
$urlLinks = foreach ($u in $url) {
    if (-not $u) { continue }
    $c = $caption[$count] 
    New-Object PSObject -Property @{
        Url = $u
        Caption = $c
    }
    $count++
}

if ($urlLinks) {
    $urlLinks = $urlLinks|
        Write-Link -Horizontal -Button -Style @{"padding" = "6px" }
}
$urlLinks|    
    New-Region -LayerID HeaderContainer -Style @{        
        "color" = "$HeaderTextColor"
        "margin-right" = "17%"
        "letter-spacing" = "1.1px"
        "padding" = "4px"
        "min-width" = "350px"
        "max-width" = "960px"
        "font-size" = "xx-small"
        "float" = "right"
    } |
    New-Region -LayerID PageSecondHeader -Style @{
        width = "100%"
        "height" = "40px"
        "background-image" = "none"
        "background-attachment" = "scroll"
        "background-repeat" = "repeat"        
        "background-position-x" = "0%"
        "background-position-y" = "0%"
        "background-origin" = "padding-box"
        "background-clip" = "border-box"
        "background-size" = "auto"
        "background-color" = "$SecondColor"
        "color" = "#fff"
    }    
    
$thing |
    New-Region -LayerID MainContainer -Style @{        
        
        "margin-right" = "auto"
        "margin-left" = "auto"
        "margin-top" = ".5em"
        "letter-spacing" = "-1px"
        "padding-right" = "40px"
        "padding-left" = "40px"
        "min-width" = "350px"
        "max-width" = "960px"
        "font-size" = "medium"
                
        "text-align" = "left"
    } |
    New-Region -LayerID MainContent -Style @{
        width = "66%"
        "height" = "40px"
        "background-image" = "none"
        "background-attachment" = "scroll"
        "background-repeat" = "repeat"        
        "background-position-x" = "0%"
        "background-position-y" = "0%"
        "background-origin" = "padding-box"
        "background-size" = "auto"
        "background-color" = "$ThirdColor"
        "color" = "$mainTextcolor"
        
    } 
    
            
            }
            
            $loadFilesInSet = {
                            
                if ($_.PSIsContainer) { return }
                
                if ($_.Fullname -like '*.psd1') {
                    # Treat as a data file
                    
                    Import-PSData -FilePath $_.fullname -AllowCommand ConvertFrom-Markdown, Write-ScriptHTML, Write-Link, New-Region, New-WebPage, Out-HTML, Add-Member |
                        Add-Member NoteProperty FullName $fullname -Force -PassThru
                } else {
                    $_
                }
            } 
            
            
            $optionalStyleSheet = @{
            
            }
            
            if ($pipeworksManifest.gallery.StyleSheet) {
                $optionalStyleSheet.StyleSheet = $gallery.StyleSheet
            }
            
            
            
            
            $sortSetItems = {
                if ($_.DatePublished) {
                    [DateTime]$_.DatePublished 
                } elseif ($_.Timestamp) {
                    [DateTime]$_.Timestamp
                } elseif ($_.LastWriteTime) {
                    $_.LastWriteTime
                }
            }                         
            
            
            $renderLayers = {
                if ($collection.StyleSheet) {
                    $optionalStyleSheet.StyleSheet = $collection.StyleSheet
                }
                $thingTitle= 
                    if ($itemIdentifier) { 
                        "$($CollectionFriendlyName) | $($itemIdentifier)"
                        $exactMatch = $popouts.Keys | Where-Object { $_ -eq $itemIdentifier }
                        if ($exactMatch) {
                            $Newpopouts = @{}
                            $Newpopouts[$itemIdentifier] = $popouts[$itemIdentifier] 
                            $popOuts = $Newpopouts
                        }
                    } else {
                        "$($CollectionFriendlyName)"
                    }
                    
                    
                
                if ($popouts.Count -gt 1) {
                    if ($Collection.Directory) {
                        $thingHtml = New-Region -LayerID InventoryItems -Order $order -Layer $popouts  -AsPopout
                        & $showThing @colorScheme -Name $thingTitle -Thing $thingHtml |
                            New-WebPage -Title $thingTitle -UseJQueryUI @optionalStyleSheet
                    } elseif ($Collection.Partition) {
                        $thingHtml =  
                            New-Region -LayerID InventoryItems -Order $order -Layer $popouts -LayerUrl $popoutUrls -AsPopout 
                        & $showThing @colorScheme -Name $thingTitle -Thing $thingHtml |
                            New-WebPage -Title $thingTitle  -UseJQueryUI @optionalStyleSheet
                    }
                } else {

                    if ($Collection.Directory) {
                        if ($order) {
                            $exactMatch = @($order -eq $itemIdentifier)
                            
                            if ($exactMatch.Count -eq 1 ) {
                                $name = "$($exactMatch)"
                                $thingHtml = $popouts[$name]                            
                            } else {
                                $thingHtml = "$($popouts[$order])"
                            }                            
                            & $showThing @colorScheme -Name $thingTitle -Thing $thingHtml |
                                New-WebPage -Title $thingTitle -UseJQueryUI @optionalStyleSheet

                        } else {                        
                            
                            #$thingHtml = $popouts[$name]
                            & $showThing @colorScheme -Name $thingTitle -Thing "<h3>Topic $Name not found</h3>" |
                                New-WebPage -Title $thingTitle -UseJQueryUI @optionalStyleSheet

                        }
                    } elseif ($Collection.Partition) {
                    
                        $name = ""
                        $realThing = Get-AzureTable -TableName $pipeworksManifest.Table.Name -Partition $Collection.Partition -Row  ($items).RowKey 
                        $thingHtml = $realThing | 
                            Out-HTML -ItemType $realThing.pstypenames[-1]
                        & $showThing @colorScheme -Name $thingTitle -Thing $thingHtml |
                            New-WebPage -Title $thingTitle -UseJQueryUI @optionalStyleSheet
                        
                        # Get the row
                    }
                }
            }
            
            $handleLayers = {
                
                $items += $_
                $layername = 
                    if ($_.Name) {
                        if ($_.Extension) {
                            # Pick out everything up to the first .
                            $_.Name.Substring(0, $_.Name.IndexOf(".") - 1)
                        } else {
                            $_.Name
                        }
                    } else {
                        " " + ($order.Count + 1)
                    }
                
                if ($Collection.Partition -and $_.RowKey) {
                    $popoutUrls[$layername] = ("../" * $depth) + "Module.ashx?id=$($Collection.Partition):$($_.RowKey)"
                    $popouts[$layername] = " "                                        
                } elseif ($Collection.Directory) {
                    if ($_ -is [IO.FileInfo]) {
                        if ($_.Extension -eq '.md') {
                            $popouts[$layername] = [IO.File]::ReadAllText($_.fullname) |
                                ConvertFrom-Markdown
                        } elseif ($_.Fullname -like '*demo.ps1' -or 
                            $_.Fullname -like '*walkthru.help.txt' -or
                            $_.fullname -like '*demo.txt') {
                            $popouts[$layername] = Write-WalkthruHTML -WalkThru (Get-Walkthru -File $_.FullName)
                        } elseif ($_.Extension -eq '.ps1') {
                            $popouts[$layername] = & $_.Fullname | Out-HTML 
                        }
                    } else {
                        $itemType = $_.pstypenames[-1]
                        $popouts[$layername]  = $_ | Out-HTML -ItemType $itemType
                    }
                    # Read files that can be read
                }
                $order += $layername
            } 

            $initLayers = {
                $popouts = @{}
                $popoutUrls = @{}
                $items = @()
                $order = @()
                $depth = 0
                if ($request -and 
                    $request.Params -and 
                    $request.Params["HTTP_X_ORIGINAL_URL"]) {
                
                    $originalUrl = $context.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

                    $pathInfoUrl = $request.Url.ToString().Substring(0, $request.Url.ToString().LastIndexOf("/"))
                            
                        
                        
                    $pathInfoUrl = $pathInfoUrl.ToLower()
                    $protocol = ($request['Server_Protocol'].Split("/", [StringSplitOptions]"RemoveEmptyEntries"))[0]  # Split out the protocol
                    $serverName= $request['Server_Name']                     # And what it thinks it called the server

                    $fullOriginalUrl = $protocol.ToLower() + "://" + $serverName + $request.Params["HTTP_X_ORIGINAL_URL"]
                    $fullOriginalUrl  = $fullOriginalUrl.ToLower()
                    $pathInfoUrl = $pathInfoUrl.ToLower()
                    $relativeUrl = $fullOriginalUrl.Replace("$pathInfoUrl", "")            
                   
                    if ($relativeUrl -like "*/*") {
                        $depth = @($relativeUrl -split "/" -ne "").Count - 1                    
                        if ($fullOriginalUrl.EndsWith("/")) { 
                            $depth++
                        }                                        
                    } else {
                        $depth  = 0
                    }
                }
                $colorScheme=  @{}
                if ($pipeworksManifest.Gallery.HeaderPrimaryColor) {
                    $colorScheme["FirstColor"] = $pipeworksManifest.Gallery.HeaderPrimaryColor
                }
                
                if ($collection.HeaderPrimaryColor) {
                    $colorScheme["FirstColor"] = $collection.HeaderPrimaryColor
                }
                
                
                
                if ($pipeworksManifest.Gallery.HeaderSecondaryColor) {
                    $colorScheme["SecondColor"] = $pipeworksManifest.Gallery.HeaderSecondaryColor
                }
                
                if ($collection.HeaderSecondaryColor) {
                    $colorScheme["SecondColor"] = $collection.HeaderSecondaryColor
                }
                
                if ($pipeworksManifest.Gallery.MainColor) {
                    $colorScheme["ThirdColor"] = $pipeworksManifest.Gallery.MainColor
                }
                
                if ($pipeworksManifest.Gallery.MainTextColor) {
                    $colorScheme["MainTextColor"] = $pipeworksManifest.Gallery.MainTextColor
                }
                
                if ($pipeworksManifest.Gallery.HeaderTextColor) {
                    $colorScheme["HeaderTextColor"] = $pipeworksManifest.Gallery.HeaderTextColor
                }
                    
            }

            $renderObjects = @{
                Begin = $initLayers
                Process = $handleLayers
                End = $renderLayers    
            } 


            
            
            
            if ($relativeUrl -eq "/" -or -not $relativeUrl) {
                # Display the page
            
            
            }
            
            
            $CollectionName, $itemIdentifier = $relativeUrl.Split("/", [StringSplitOptions]"RemoveEmptyEntries")
            
            if ($CollectionNames -notcontains $CollectionName) {
                if (-not $pipeworksManifest.Gallery.DefaultCollection) {
                    Write-Error "No collection named $($CollectionName). Try $CollectionNames. <br/> Relative URL was: $relativeUrl . <br/> Original URL was: $fullOriginalUrl"
                    return
                } else {
                    # There's a default collection, so the collection name attempted value is really the item identifier
                    $ItemIdentifier = $CollectionName
                    $CollectionName = $pipeworksManifest.Gallery.DefaultCollection
                    
                }
            }
            
            $Collection = $Collections | Where-Object { $_.Name -eq $CollectionName -or $_.Name -contains $CollectionName} 
            $CollectionFriendlyName =
                    if ($Collection.FriendlyName) {
                        $Collection.FriendlyName
                    } else {
                        $CollectionName
                    }
            
            if ($collection.SortBy) {
                $sortSetItems = @{
                    Property = $collection.SortBy
                } 
            } else {
                $sortSetItems = @{
                    Property = $sortSetItems
                    Descending = $true
                }
                
            }
            if (-not $ItemIdentifier) {
            
                 
                    if ($collection.Directory) {
                        # Getting all of the items is reasonable, so do so
                        Get-ChildItem -Path "bin\$($module.Name)\$($Collection.Directory)" -Recurse |
                            ForEach-Object $loadFilesInSet |
                            Sort-Object @sortSetItems  |                            
                            ForEach-Object @renderObjects
                    } elseif ($collection.Partition) {
                        $selectItems = (@($Collection.By) + "RowKey" + "Name") | Select-Object -Unique
                            Search-AzureTable -TableName $pipeworksManifest.Table.Name -Filter "PartitionKey eq '$($Collection.Partition)'" -StorageAccount $storageAccount -StorageKey $storageKey -Select $selectItems |
                            Sort-Object @sortSetItems |
                            ForEach-Object @renderObjects
                    }
            
                <## Render the gallery instead of complain
                & $showThing @colorScheme -Name "$($CollectionFriendlyName) | No Item Identifier" -Thing $thingHtml |
                    New-WebPage -Title "$($CollectionFriendlyName) | No Item Identifier" -UseJQueryUI
                                     
                  #>
  
                return
            }            

            $itemIdentifier = foreach ($i in $itemIdentifier) {
                [Web.httpUtility]::UrlDecode($i)
            }

            if ($itemIdentifier.Count) {
                
                
                
                
                
            } else {
                # One one ID
                
                
                             
                
                
                if ($Collection.Partition) {                    
                    $selectItems = (@($Collection.By) + "RowKey" + "Name") | Select-Object -Unique
                    $ItemsInSet = Search-AzureTable -TableName $pipeworksManifest.Table.Name -Filter "PartitionKey eq '$($Collection.Partition)'" -StorageAccount $storageAccount -StorageKey $storageKey -Select $selectItems               
                } elseif ($Collection.Directory) {
                    $ItemsInSet  = Get-ChildItem -Path "bin\$($module.Name)\$($Collection.Directory)" -Recurse |
                        ForEach-Object $loadFilesInSet 
                }
                
                
                # Calculate the depth of the virtual URL compared to the real page.
                # This gets used to convert links to local resources, such as a custom JQuery theme
                
                $depth =0 
                if ($relativeUrl -like "*/*") {
                    $depth = @($relativeUrl -split "/" -ne "").Count - 1                    
                    if ($fullOriginalUrl.EndsWith("/")) { 
                        $depth++
                    }                    
                    
                } else {
                    $depth  = 0
                }
                
                
                
                
                
                
                foreach ($byTerm in $Collection.By) {
                    $ItemsInSet |
                        Sort-Object @sortSetItems | 
                        Where-Object {
                            $_.$byTerm -ilike "*${itemIdentifier}*"
                        } |
                        ForEach-Object @renderObjects
                        
                }
                   
            }
            
            
            return

        
         }      
        
        # If the gallery is public, then there is a page to add items if the person is logged in
        if ($parameter.IsPublic) {
        
        }
        
               
        @{
            "AnyUrl.pspage" = "<| $anyPage |>"
            
        }                                   
    }        
}