

function stackEnclosure(viewName, showOnKey, labelText, subViewMarkup)
{
	return stackEnclosureReadout(viewName, showOnKey, labelText, null, subViewMarkup);
}

function stackEnclosureReadout(viewName, showOnKey, labelText, readoutValueKey, subViewMarkup)
{
	var labelName = "none";
	if (labelText != null)
		labelName = viewName + "Label";
	
	return {
		nsClass: "GXDrawView",
		gxShowOnKey: showOnKey,
		gxLayout: [
			"V:|-(-999)-[self(34)]",		// vertical position set by parent
			"H:|-0-[self]-0-|",
		],
		gxViewName: viewName + "Enclosure",
		gxChildViews:
		{
			[labelName]: labelView(labelText, "right", readoutValueKey),
			[viewName]: subViewMarkup,
		},
	};
}



markup.push({

	// MARK: block

	BroadcastBlock:
    {
		"+": "OutputTemplate",
        geNodeClass: "GEShoutcastNode",
		gxFaceModel: {
			nsClass: "AH4ShoutcastViewModel",
			gxFaceModelKeyPath: "faceModel",
		},
        h4PresetsId: "BroadcastPresets4",
		gxTitle: "Broadcast",
		gxLibraryDescription: "Stream audio to an online radio server",
		geOutputRank: 4, 	// outputs have an order of importance for status display
		geOutputVerb: "Broadcasting",
		gxLibraryIcon: "library.broadcast",
		gxPopoverInfo: "BroadcastPopover",
		gxChildViews:
		{
			status: {
				"+": "LabelView.top.foreColorTheme1.mediumWeight.size14",
				gxFrameRect: "12,42,96,22",
				gxValueKey: "node.displayState",
				axTitle: "broadcast status",
                axIsIgnored: false,
			},
			streamTime: {
				"+": "LabelView.blockReadout.top",
				gxFrameRect: "12,62,96,22",
				gxFormatter: { nsClass:"PTTrackTimeFormatter" },
				gxValueKey: "node.streamTime",
                gxAnimateOnKey: "running",
                gxHideOnNilValue: true,
                axTitle: "broadcast duration",
                axIsIgnored: false,
			},
			details: {
				"+": "LabelView.blockReadout",
				gxFrameRect: "12,84,96,16",
				gxValueKey: "node.metaTitle",
                gxAnimateOnKey: "running",
                axTitle: "current track title",
                axIsIgnored: false,
			},
		}
	},

	// MARK: - popover

	BroadcastPopover:
	{
		"+": "PopoverTemplate",
		gxTitle: "Broadcast",
		gxLayout: [
			"H:|-12-[self(450)]-14-|",
			"V:|-12-[self]-12-|",

			"V:|-35-[errorHolder]-6-[statusTab]-(-13)-[panels]-8-[presetsGroup]",

            "H:|-52-[statusTab]-(1)-[metaTab(==statusTab)]-(1)-[setupTab(==statusTab)]-52-|&alignBaseline",
        ],
		gxChildViews:
		{
			title: "PopoverTitle",
            switch: "PopoverOnOffSwitch",
			presetsGroup: presetsGroup(),
            errorHolder:
            {
                nsClass: "GXExpandingView",
                axIsIgnored: true,
                gxDefaultValue: false,   // expanded!
				gxValueKey: "node.hasErrorMessage",
				gxExpandedSize: 105,
                gxLayout:
                [
                    "H:|-0-[self]-(-1)-|",
                    "H:|-0-[error]-0-|",
                    "H:[retry(95)]-15-|",
                    "V:|-8-[error(82)]-(-32)-[retry(20)]",
                ],
                gxChildViews:
                {
                    error:
                    {
                        "+": "LabelView.top.left.size12.wrap",
                        gxValueKey: "node.errorMessageForDisplay",
                        gxForePainter: {
                            "+": "LabelFore.top.left.size12.wrap",
                            gxFontColor: errorColor(95),
                            gxEdgeInsets: "12, 10, 12, 0"
                        },
                        gxBackPainter: {
							nsClass: "GXPainter",
							gxFillColor: errorColor(20),
						},
                    },
					retry:
					{
						"+": "RunButton",	// run button style to stand out?
						gxValueKey: "node.retryButtonValue",
						gxLayerZPosition: 10,
						gxTitle: "Retry",
                	},
				}
            },
            statusTab: {
                "+": "TabButtonView.leftSegment",
                gxTitle: "Status",
                gxValueKey: "node.statusShown",
				axRoleDescription: "Tab, 1 of 3"
            },
            metaTab: {
                "+": "TabButtonView.middleSegment",
                gxTitle: "Metadata",
                axTitle: "Meta data",
                gxValueKey: "node.metadataShown",
				axRoleDescription: "Tab, 2 of 3"
            },
            setupTab: {
                "+": "TabButtonView.rightSegment",
                gxTitle: "Setup",
                gxValueKey: "node.setupShown",
				axRoleDescription: "Tab, 3 of 3"
            },
            panels:
            {
            	nsClass: "GXExpandingView",
				gxDefaultValue: true,	// expanded
                axIsIgnored: true,
				axFrameInsets: "0, 20, 0, 0",	// avoid overlaps with tabs so nav order is improved
            	gxLayout:
            	[
            		"H:|-0-[self]-0-|",
            		"V:|-0-[statusPanel]",
                    "V:|-0-[metaPanel]",
                    "V:|-0-[setupPanel]",
            	],
            	gxChildViews:
            	{
					statusPanel: { "+": "BroadcastStatusPanel" },
					metaPanel: { "+": "BroadcastMetaPanel" },
					setupPanel: { "+": "BroadcastSetupPanel" },
            	}
            },
		}
	},

	// MARK: - status panel
	
	BroadcastStatusPanel:
	{
		nsClass: "GXDrawView",
		gxShowOnKey: "node.statusShown",
		axIsIgnored: false,
		axTitle: "Status Group",
		axFrameInsets: "0, 20, 0, 0",	// avoid overlaps with tabs so nav order is improved
		gxLayout:
		[
			"H:|-0-[self]-0-|",
			"V:|-0-[connection]-6-[metadata(235)]-0-|",
		],
		gxChildViews:
		{
			connection:
			{
				"+": "GroupView",
				axIsIgnored: true,
				gxLayout:
				[
					"H:|-0-[self]-0-|",
					"H:|-12-[stateLabel(127)]-8-[state]-14-|&alignBaseline",
					"H:|-12-[durationLabel(127)]-8-[duration]-14-|&alignBaseline",
					"H:|-12-[dataLabel(127)]-8-[data]-14-|&alignBaseline",
				 
					"V:|-22-[connectionheading]-10-[state]-8-[duration]-8-[data]-14-|",
				],
				gxChildViews:
				{
					connectionheading: groupTitleView("Connection"),
					stateLabel: labelView("Status:"),
					state:
					{
						"+": "LabelView.top.left.colorThemeLive2",
						gxDefaultValue: "Offline",
						gxValueKey: "node.displayState",
						axTitle: "Status",
						axIsIgnored: false,
					},
					durationLabel: labelView("Duration:"),
					duration:
					{
						"+": "LabelView.top.left.colorThemeLive2",
						gxValueKey: "node.streamTime",
						gxFormatter: { nsClass:"PTTrackTimeFormatter" },
						axTitle: "Duration",
						axIsIgnored: false,
					},
					dataLabel: labelView("Data Transfered:"),
					data:
					{
						"+": "LabelView.top.left.colorThemeLive2",
						gxValueKey: "node.streamSize",
						axTitle: "Data Transfered",
						axIsIgnored: false,
					},
				},
			},
			metadata:
			{
				"+": "GroupView.noTopStroke",
				axIsIgnored: true,
				gxLayout:
				[
					"H:|-0-[self]-0-|",
					
					"H:|-12-[nameLabel(127)]-8-[name]-14-|&alignBaseline",
					"H:|-12-[titleLabel(127)]-8-[title]-14-|&alignBaseline",
					"H:|-12-[artworkLabel(127)]-8-[artwork(128)]&alignTop",
					
					"V:|-6-[metadataHeading]-10-[name]-8-[title]-8-[artwork(128)]",
				],
				gxChildViews:
				{
					// expand button view
					metadataHeading: groupTitleView("Current Metadata"),
					nameLabel: labelView("Station Name:"),
					name:
					{
						"+": "LabelView.top.left.foreColor1.size12",
						gxValueKey: "node.name",
						axTitle: "Station Name",
						axIsIgnored: false,
					},
					titleLabel: labelView("Now Playing:"),
					title:
					{
						"+": "LabelView.top.left.foreColor1.size12",
						gxValueKey: "node.metaTitle",
						axTitle: "Now Playing",
						axIsIgnored: false,
					},
					artworkLabel:
					{
						"+": "LabelView.right.size13",
						gxDefaultValue: "Artwork:",
						gxShowOnKey: "node.usesStationLogo",
					},
					artwork:
					{
						"+": "ArtView.noDefaultText",
						gxIsEditable: false,
						gxShowOnKey: "node.usesStationLogo",
						gxValueKey: "node.metaArtwork",
						axIsIgnored: true,
					}
				}
			}
		}
	},

	
	// MARK: metadata panel
	BroadcastMetaPanel:
	{
		nsClass: "GXDrawView",
		gxShowOnKey: "node.metadataShown",
		axIsIgnored: false,
		axTitle: "Metadata Group",
		axFrameInsets: "0, 20, 0, 0",	// avoid overlaps with tabs so nav order is improved
		gxLayout:
		[
			"H:|-0-[self]-0-|",
			"V:|-0-[metaSection]-6-[trackSection]-0-|",
		],
		gxChildViews:
		{
			metaSection:
			{
				"+": "GroupView",
				axIsIgnored: true,
				gxLayout: [
					"H:|-0-[self]-0-|",
					"H:|-12-[nameLabel(60)]-8-[name]-14-|&alignBaseline",
					"H:|-12-[urlLabel(60)]-8-[url]-14-|&alignBaseline",
					"H:|-12-[genreLabel(60)]-8-[genre]-14-|&alignBaseline",
					"H:|-12-[logoLabel(60)]-8-[logo(100)]&alignTop",

					"V:|-22-[infoHeading]-8-[name]-8-[url]-8-[genre]-8-[logo(100)]-15-|",
				],
				gxChildViews:
				{
					infoHeading: groupTitleView("Station Info"),
					nameLabel: labelView("Name:"),
					name:
					{
						"+": "DarkTextField",
						gxValueKey: "node.name",
						axTitle: "Station Name",
					},
					urlLabel: labelView("URL:"),
					url:
					{
						"+": "DarkTextField",
						gxValueKey: "node.url",
						axTitle: "Station URL",
					},
					genreLabel: labelView("Genre:"),
					genre:
					{
						"+": "GenreSelectorField",
						gxValueKey: "node.genre",
						axTitle: "Genre",
					},
					logoLabel:
					{
						"+": "LabelView.right.size12",
						gxShowOnKey: "node.usesStationLogo",
						gxDefaultValue: "Logo:",
					},
					logo:
					{
						"+": "ArtView",
						gxShowOnKey: "node.usesStationLogo",
						gxValueKey: "node.logo",
						axTitle: "Logo",
						axHelp: "Paste station logo artwork here",
					},
				},
			},
			trackSection:
			{
				"+": "GroupView.noTopStroke",
				axIsIgnored: true,
				gxLayout:
				[
					"H:|-0-[self]-0-|",
					"H:|-12-[titlesLabel(90)]-8-[titles]-14-|&alignBaseline",
					"H:|-12-[sourceLabel(90)]-8-[source]-14-|&alignBaseline",
						   
					"V:|-6-[trackHeading]-8-[titles]-8-[source]-15-|",
				],
				gxChildViews:
				{
					trackHeading: groupTitleView("Track Titles"),
					titlesLabel: labelView("Track Format:"),
					titles:
					{
						"+": "TrackTitleTokenField",
						gxValueKey: "node.trackTitlesFormat",
						gxBaselineOffset: 6,
						axTitle: "Track Titles Format",
						axHelp: "Tokens can be added to this field from the context menu",
					},
					sourceLabel: labelView("Track Source:"),
					source: {
						nsClass: "GETitleSourceAppPopupView",
						gxValueKey: "node.sourceAppPath",
						defaultAppIcon: "app.icon.generic.small",
						gxIntrinsicHeight: 25,
						gxBackPainter: "ControlBack",
						gxTitlePainter: {
							"+": "ControlFore.left.useMarkup",
							gxEdgeInsets: "28,0,0,0",
						},
						gxArrowPainter: "PopupArrows",
						gxIconPainter: {
							"+": "ImagePainter.left",
							gxEdgeInsets: "5, 4, 0, 3",
						},
						axTitle: "Track Titles Source Application",
						axHelp: "A source application that can provide track data as it plays.",
					},
				},
			},
		},
	},
	
	
	// MARK: setup panel
	
	BroadcastSetupPanel:
	{
		nsClass: "GXDrawView",
		gxShowOnKey: "node.setupShown",
		axIsIgnored: false,
		axTitle: "Setup Group",
		axFrameInsets: "0, 20, 0, 0",	// avoid overlaps with tabs so nav order is improved
		gxLayout:
		[
			"H:|[self]|",
			"V:|-0-[server]-6-[encoding]-0-|",
		],
		gxChildViews:
		{
			server:
			{
				nsClass: "GXStackView",
				gxBackPainter: "GroupViewBack",
				gxDefaultValue: true,	// expanded
				gxTopHeight: 9,
				gxExtraSize: 14,
				gxCanDrawSubviewsIntoLayer: false,  // needed to override true setting, which leads to updates being missed when tab hidden
				axTitle: "Server Settings Group",
				gxLayout:
				[
					"H:|-0-[self]-0-|",
				],
				gxChildViews:
				[
					stackEnclosure( "serverHeading", "", null,
					{
						"+": "GroupTitleView",
						gxDefaultValue: "Server",
						gxLayout: [ "V:|-12-[self]", "H:|-14-[self]" ],
					}),
					stackEnclosure( "type", "", "Server Type:",
					{
						"+": "BroadcastServerTypesPopup",
						axTitle: "Server Type",
						gxDefaultValue: 0,
					}),
					stackEnclosure( "host", "", "Server Address:",
					{
						"+": "BroadcastTextField",
						gxValueKey: "node.hostName",
						axTitle: "Server Address",
					}),
					stackEnclosure( "port", "", "Port:",
					{
						"+": "BroadcastTextField",
						gxValueKey: "node.port",
						axTitle: "Server Port",
					}),
					stackEnclosure( "user", "node.usesStreamIDField", "User:",
					{
						"+": "BroadcastTextField",
						gxValueKey: "node.UID",
						axTitle: "User",
					}),
					stackEnclosure( "password", "", "Password:",
					{
						"+": "BroadcastTextField",
						nsClass: "GXPasswordField",
						gxValueKey: "node.password",
						axTitle: "Password",
					}),
					stackEnclosureReadout( "streamID", "node.usesStreamIDField", "NOT Stream ID:", "node.streamIDLabelText",
					{
						"+": "BroadcastTextField",
						gxValueKey: "node.streamID",
						gxShowOnKey: "node.usesStreamIDField",
						axTitle: "Stream ID or Mountpoint",
					}),
				]
			},
			encoding:
			{
				"+": "ExpandingGroupView.noStroke",
				gxDefaultValue: true,	// expanded
				axIsIgnored: false,
				axTitle: "Encoding Format Group",
				gxLayout:
				[
					"H:|-0-[self]-0-|",
					"H:[encodingHeading]-(8)-[description]-17-|&alignBaseline",
					"H:|-12-[presetFormatLabel(80)]-8-[presetFormat(250)]&alignBaseline",
					
					"V:|-6-[encodingHeading]-8-[presetFormat]-14-[advancedBtn]-0-[advancedSection]"
				],
				gxChildViews:
				{
					encodingHeading: groupTitleView("Encoding Format"),
					presetFormatLabel: labelView("Quality:"),
					presetFormat: {
						"+": "EncoderPresetFormatPopupMenu",
						axTitle: "Quality",
						axHelp: "Choose from several preset encoding formats",
					},
					description: {
						"+": "LabelView.right.darkest.size115",
						gxValueKey: "node.encodingFormat.briefDisplayDescription",
					},
					advancedBtn: {
						"+": "AdvancedGroupButton",
						gxTitle: "<disclosure/> Advanced Encoding Options",
						axFormatter: disclosureAxFormatter("Advanced Encoding Options"),
						gxValueKey: "node.showAdvancedFormat"
					},
					advancedSection:
					{
						nsClass: "GXStackView",
						gxBackPainter: "GroupViewBack.noTopStroke",
						gxDefaultValue: false, // collapsed
						gxCollapsedSize: 1,
						gxExtraSize: 10,
						gxValueKey: "node.showAdvancedFormat",
						gxLayout: "H:|-0-[self]-0-|",
						gxChildViews:
						[
							// expand button view
							// format type
							stackEnclosure( "format", "", "Format:",
							{
								"+": "BroadcastPopupMenu",
								gxValueKey: "node.encodingType",
								gxMenuItemsKeyPath: "node.encodingTypeMenuItems",
								gxLayout: [ "H:[selfLabel]-[self]&alignBaseline",
										   //"H:[superview(380)]",
										"H:|-85-[self]-14-|", "V:|-4-[self]" ],
								axTitle: "Format"
							}),
							// bit rate
							stackEnclosure( "bitRate", "", "Bit Rate:",
							{
								"+": "BroadcastPopupMenu",
								gxValueKey: "node.__formatkey__bitrate",
								gxMenuItemsKeyPath: "node.bitrateMenuItems",
								axTitle: "Bit Rate"
							}),
							// bit rate mode
							stackEnclosure( "bitRateMode", "node.bitrateModeShown", "Bit Rate Mode:",
							{
								"+": "BroadcastPopupMenu",
								gxValueKey: "node.__formatkey__bitrateMode",
								gxMenuItemsKeyPath: "node.bitrateModeMenuItems",
								axTitle: "Bit Rate Mode"
							}),
							// sample rate
							stackEnclosure( "sampleRate", "node.sampleRateShown", "Sample Rate:",
							{
								"+": "BroadcastPopupMenu",
								gxValueKey: "node.__formatkey__samplerate",
								gxMenuItemsKeyPath: "node.sampleRateMenuItems",
								axTitle: "Sample Rate"
							}),
							// channels
							stackEnclosure( "sampleRate", "", "Channels:",
							{
								"+": "BroadcastPopupMenu",
								gxValueKey: "node.__formatkey__channels",
								gxMenuItemsKeyPath: "node.channelsMenuItems",
								axTitle: "Channels"
							}),
						]
					}
				}
			},
		}
	},

	// MARK: - preset formats

	EncoderPresetFormatPopupMenu:
	{
		"+": "PopupMenuTemplate",
		gxValueKey: "node.presetFormatID",
		gxDisableOnKey: "running",
		gxMenuItems:
		[
			{	gxTitle: "-MP3 Streaming" },
			{	gxTitle: ">Spoken Word",					gxValue: "BCMP3_32" },
			{	gxTitle: ">Medium Quality",					gxValue: "BCMP3_128" },
			{	gxTitle: ">High Quality",					gxValue: "BCMP3_256" },
			{	gxTitle: "-AAC Streaming" },
			{	gxTitle: ">Spoken Word",					gxValue: "BCAAC_32" },
			{	gxTitle: ">Medium Quality",					gxValue: "BCAAC_128" },
			{	gxTitle: ">High Quality",					gxValue: "BCAAC_256" },
			{	gxTitle: "-" },
			{	gxTitle: "Custom...",						gxValue: "" }
		]
	},

	// MARK: - genre selector

	GenreSelectorField: {
		"+": "DarkTextField",
        gxButtonForePainter:
        {
            "+": "PopupArrows",
            gxDefaultSize: "28, 22",    // required
            gxTintColor: "ForeColor2",
            hover: {
                gxTintColor: "ForeColor1",
            }
        },
		gxLineBreakMode: 0,	// word wrap, not default truncate tail.
		// menu of tokens as displayed to user
		gxMenuItems:
		[
			{	gxTitle: "Alternative",			gxValue: "Alternative" },
			{	gxTitle: "Arabic",				gxValue: "Arabic" },
			{	gxTitle: "Blues",				gxValue: "Blues" },
			{	gxTitle: "Brazilian",			gxValue: "Brazilian" },
			{	gxTitle: "Children's Music",	gxValue: "Children's Music" },
			{	gxTitle: "Chinese",				gxValue: "Chinese" },
			{	gxTitle: "Christian & Gospel",	gxValue: "Christian & Gospel" },
			{	gxTitle: "Classical",			gxValue: "Classical" },
			{	gxTitle: "Comedy",				gxValue: "Comedy" },
			{	gxTitle: "Country",				gxValue: "Country" },
			{	gxTitle: "Cuban",				gxValue: "Cuban" },
			{	gxTitle: "Dance",				gxValue: "Dance" },
			{	gxTitle: "Easy Listening",		gxValue: "Easy Listening" },
			{	gxTitle: "Electronic",			gxValue: "Electronic" },
			{	gxTitle: "Enka",				gxValue: "Enka" },
			{	gxTitle: "Fitness",				gxValue: "Fitness" },
			{	gxTitle: "Folk",				gxValue: "Folk" },
			{	gxTitle: "Hip-Hop / Rap",		gxValue: "Hip-Hop / Rap" },
			{	gxTitle: "Holiday",				gxValue: "Holiday" },
			{	gxTitle: "Indian",				gxValue: "Indian" },
			{	gxTitle: "Instrumental",		gxValue: "Instrumental" },
			{	gxTitle: "Jazz",				gxValue: "Jazz" },
			{	gxTitle: "Karaoke",				gxValue: "Karaoke" },
			{	gxTitle: "Korean",				gxValue: "Korean" },
			{	gxTitle: "Latino",				gxValue: "Latino" },
			{	gxTitle: "Marching",			gxValue: "Marching" },
			{	gxTitle: "New Age",				gxValue: "New Age" },
			{	gxTitle: "Orchestral",			gxValue: "Orchestral" },
			{	gxTitle: "Pop",					gxValue: "Pop" },
			{	gxTitle: "R&B/Soul",			gxValue: "R&B/Souls" },
			{	gxTitle: "Reggae",				gxValue: "Reggae" },
			{	gxTitle: "Rock",				gxValue: "Rock" },
			{	gxTitle: "Soundtrack",			gxValue: "Soundtrack" },
			{	gxTitle: "Spoken",				gxValue: "Spoken" },
			{	gxTitle: "Spoken Word",			gxValue: "Spoken Word" },
			{	gxTitle: "World",				gxValue: "World" },

		],
		gxTokenNames:
		{
			
		},
	},

	TrackTitleTokenField: {
		"+": "TokenField",
		gxMenuItems:	// menu of tokens as displayed to user
		[
			{	gxTitle: "Album",			gxValue: "%album" },
			{	gxTitle: "Artist",			gxValue: "%artist" },
			{	gxTitle: "Track Title",		gxValue: "%track" },
		],
		gxTokenNames:
		{
			"%album":				"Album",
			"%artist":				"Artist",
			"%track":				"Track Title",
		},
	},

	
	// MARK: - setup templates

	BroadcastServerTypesPopup:
	{
		"+": "PopupMenuTemplate",
		gxValueKey: "node.version",
		gxDisableOnKey: "running",
		gxLayout: [
			"H:|-12-[selfLabel(80)]-8-[self(250)]&alignBaseline",
			"V:|-4-[self]",
		],
		gxMenuItems:
		[
		 	{	gxTitle: "Shoutcast 2",		gxValue: 2 },
		 	{	gxTitle: "Shoutcast 1",		gxValue: 1 },
			 {	gxTitle: "Icecast 2",		gxValue: 3 },
		]
	},
	
	BroadcastPopupMenu: {
		"+": "PopupMenuTemplate",
		gxDisableOnKey: "running",
		gxLayout: [
			"H:[selfLabel]-[self]&alignBaseline",
			"H:|-130-[self]-32-|",
			"V:|-6-[self]"
		]
	},

	BroadcastTextField:
	{
		"+": "DarkTextField",
		gxDisableOnKey: "running",
		gxLayout: [
			"H:|-12-[selfLabel(110)]-8-[self]-14-|&alignBaseline",
			"V:|-6-[self]"
		]
	},


})
