/**
 *  Multi Switch with Virtual Tiles for Master Switch
 *
 *  Copyright 2014 Cooper Lee
 *
 *  NOTE - THIS ONLY WORKS WITH ATTRIBUTE TYPE switch and switch[x] (1..9)
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
definition(
    name: "Multi Switch with Virtual Tiles for Master Switch",
    namespace: "ms_w_vts",
    author: "Cooper Lee",
    description: "Use this app with a device that has multiple switches embedded in the device type and it will create virtual switches for each of the various embedded switches.",
    category: "Convenience",
    iconUrl: "http://cdn.flaticon.com/png/256/25823.png",
    iconX2Url: "http://cdn.flaticon.com/png/256/25823.png",
    iconX3Url: "http://cdn.flaticon.com/png/256/25823.png")


preferences {
	page(name: "mainDevice", uninstall: true, install:false)
	page(name: "virtualSwitches", uninstall: true, install:true)
	page(name: "virtualDetails", uninstall: true, install:true)
}

def mainDevice() {
	dynamicPage(name: "mainDevice", title: "Setup virtual app and multi-switch device", nextPage: "virtualDetails", uninstall: true, install:false) {
        section {
            input "master", "capability.switch", multiple: false, required: true, title: "Choose the device with multiple switches", image: "http://cdn.flaticon.com/png/256/61163.png"
            label title: "Assign a name for this virtual tile handler", required: false
            paragraph: "Assign switches to virtual tiles or real switches on next page"
        }
	}
}

def devTemplates(devType) {
    def templates = [ 
                        "base2"		:"Device with 2 switches", 
                        "base9"		:"Device with up to 9 switches", 

						"aeon4"		:"Aeon Power Strip", 

						"iPool1PSV"	:"PE653 - Pool & Spa w/o Booster (Variable speed pump)", // (blower on sw3 lights on sw2
                        "iPool1PSVB":"PE653 - Pool & Spa w/ Booster (Variable speed pump)", // (booster on sw3 lights/blower on sw2
                        
                        "iPool1"	:"PE653 - Pool and 4 Acc (1 speed pump)", 
                        "iPool1H"	:"PE653 - Pool w/Heater and 3 Acc (1 speed pump)", 
                        "iPool1PS"	:"PE653 - Pool & Spa w/o Booster (1 speed pump)", // blower on sw3 lights on sw2
                        "iPool1PSB"	:"PE653 - Pool & Spa w/ Booster (1 speed pump)", // (booster on sw3 lights/blower on sw2
                        
                        "iPool1S"	:"PE653 - Spa Only (1 speed pump)", // blower on sw3 lights on sw2
                        "iPool2S"	:"PE653 - Spa Only (2 speed pump)", // blower on sw4 lights/booster on sw3
                        
                        "iPool2"	:"PE653 - Pool and 3 Acc (2 speed pump)", 
                        "iPool2H"	:"PE653 - Pool w/Heater and 2 Acc (2 speed pump)",  
                        "iPool2PS"	:"PE653 - Pool & Spa w/o Booster  (2 speed pump)", // blower on sw3
                        "iPool2PB"	:"PE653 - Pool w/ Booster and Lights (2 speed pump)", // (booster on sw3 lights on sw4
                    ]
    if(devType) { return devTemplates.getAt(dev_type) } else { return templates }
}


def templates() {
	def templates = [
    	'aeon4': 	[ "switch":"Power Strip", "switch1":"SW Outlet 1", "switch2":"SW Outlet 2", "switch3":"SW Outlet 3", "switch4":"SW Outlet 4", "switch5":"Outlet 1", "switch6":"Outlet 2", "switch7":"All SW Outlets"],
    	'base': 	[ "switch":"switch", "switch1":"Switch 1"],
    	'base2': 	[ "switch":"switch", "switch1":"Switch 1", "switch2":"Switch 2"],
    	'base9': 	[ "switch":"switch", "switch1":"Switch 1", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Switch 5", "switch6":"Switch 6", "switch7":"Switch 7", "switch8":"Switch 8", "switch9":"Switch 9"],
    	'iPool1': 	[ "switch1":"Pool Pump", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Switch 5"],
    	'iPool1H': 	[ "switch1":"Pool Pump", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Pool Heater"],
    	'iPool1PS':	[ "switch1":"Filter Pump", "switch2":"Water Lights", "switch3":"Spa Blower", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1PSB':[ "switch1":"Filter Pump", "switch2":"Spa Blower", "switch3":"Booster Pump", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1PSV':[ "switch1":"Filter Pump", "switch2":"Spa Blower", "switch3":"Booster Pump", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1PSVB':[ "switch1":"Filter Pump", "switch2":"Pool Lights", "switch3":"Spa Blower", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1S':	[ "switch1":"Spa Pump", "switch2":"Spa Lights", "switch3":"Spa Blower", "switch4":"Spa Accessory", "switch5":"Spa Heater"],
    	
        'iPool2': 	[ "switch1":"Pool Pump High", "switch2":"Pool Pump Low", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Switch 5"],
    	'iPool2H': 	[ "switch1":"Pool Pump High", "switch2":"Pool Pump Low", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Pool Heater"],
    	'iPool2S':	[ "switch1":"Spa Pump High", "switch2":"Spa Pump Low", "switch3":"Spa Lights", "switch4":"Spa Blower", "switch5":"Spa Heater"],
    	'iPool2PS':	[ "switch1":"Filter Pump High", "switch2":"Filter Pump Low", "switch3":"Spa Blower", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool2PB':	[ "switch1":"Pool Pump High", "switch2":"Pool Pump Low", "switch3":"Booster Pump", "switch4":"Pool Lights", "switch5":"Water Heater"],


    	'iPoolSpa':	[ "switch1":"Pump", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Pool Heater"],
        			]
    if(switch_template) { return templates.getAt(switch_template) } else { return [ "switch":"switch", "switch1":"Switch 1", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4"] }
}


def virtualDetails() {
	unsubscribe()
	syncChildDevices()
	dynamicPage(name: "virtualDetails", title: "Which virtual switches to create for $master.label?", uninstall: true, install:true) {
        
        section {
            input "switch_template", "enum", multiple: false, required: false, refreshAfterSelection:true, options:devTemplates(), title:"Template to use", description: "What device template should to use for $master.label?", image: "http://cdn.flaticon.com/png/256/25823.png"
        }

        section {
            input "switches", "enum", multiple: true, required: false, refreshAfterSelection:true, options:templates(), title:"Select Switches", description: "Choose which switches of $master.label you would like to have as separate switches", image: "http://cdn.flaticon.com/png/256/25823.png"
        }

        section("Current Virtual Switches of $master.label:") {
            def kids = getChildDevices()
            kids.each { paragraph "$it.label" }
        }
	}
}



def installed() {
	syncChildDevices()
    def kids = getChildDevices()
}

def updated() {
	syncChildDevices()
    def kids = getChildDevices()
    unsubscribe()
	kids.each { subscribe(master, "$it.name", vswitch) }
}

def uninstalled() {
	removeChildDevices()	
}

def vswitch(evt) { 
    def vswitch = evt.descriptionText.find(/switch./).replaceAll(" ","")
//	log.debug "child switch to change: $vswitch event: $evt.value  DDNI:${ddni(vswitch)}"
    def vkid = getChildDevice(ddni(vswitch))
//    log.debug "$evt.value $evt.deviceId $evt.description $evt.descriptionText"
//    log.debug "vkid: $vkid"
	vkid."${evt.value}"()
}
    
//def mswitch(evt) { log.debug "$evt.value $evt.deviceId $evt.description $evt.descriptionText" }

def on(childDevice) {
	def num = childDevice.device.name.replaceAll("switch","")
	if(num) { master."on${num}"() } else { master.on();log.debug "No switch number provided for on" }
}

def off(childDevice) {
	def num = childDevice.device.name.replaceAll("switch","")
	if(num) { master."off${num}"() } else { master.off();log.debug "No switch number provided for off" }
}


private syncChildDevices() {    
    switches.each { def e = getChildDevice(ddni(it)); if(!e) { createChild(it) } }
    def switchKids = getChildDevices()
    def removeKids = switchKids.name - switches
//    log.debug "SWs: $switches del: $removeKids kids: $removeKids"
    removeKids.each { rem ->
    	def delKid = getChildDevice(ddni(rem))
        log.debug delKid.deviceNetworkId
        removeChildDevices(delKid)
        }
}

private createChild(vt) {
		def label = templates().getAt(vt)
		log.debug "Label $label"
		def addedvt = addChildDevice("ms_w_vts", "vTile_ms", ddni(vt), null, [name:vt, label:label, completedSetup: true])
      	log.info "created Virtual Switch ${addedvt.displayName} with DNI ${addedvt.deviceNetworkId}"
}

private removeChildDevices(delete) {
	unsubscribe()
	if(!delete) { delete = getChildDevices() }
    delete.each {
        deleteChildDevice(it.deviceNetworkId)
      	log.debug "deleted ${delete.displayName}"
    }
}

private ddni(id){
	if(!state.appId) { state.appId = app.id }
	def ddni = state.appId + "/" + id
    return ddni
}/**
 *  Multi Switch with Virtual Tiles for Master Switch
 *
 *  Copyright 2014 Cooper Lee
 *
 *  NOTE - THIS ONLY WORKS WITH ATTRIBUTE TYPE switch and switch[x] (1..9)
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
definition(
    name: "Multi Switch with Virtual Tiles for Master Switch",
    namespace: "ms_w_vts",
    author: "Cooper Lee",
    description: "Use this app with a device that has multiple switches embedded in the device type and it will create virtual switches for each of the various embedded switches.",
    category: "Convenience",
    iconUrl: "http://cdn.flaticon.com/png/256/25823.png",
    iconX2Url: "http://cdn.flaticon.com/png/256/25823.png",
    iconX3Url: "http://cdn.flaticon.com/png/256/25823.png")


preferences {
	page(name: "mainDevice", uninstall: true, install:false)
	page(name: "virtualSwitches", uninstall: true, install:true)
	page(name: "virtualDetails", uninstall: true, install:true)
}

def mainDevice() {
	dynamicPage(name: "mainDevice", title: "Setup virtual app and multi-switch device", nextPage: "virtualDetails", uninstall: true, install:false) {
        section {
            input "master", "capability.switch", multiple: false, required: true, title: "Choose the device with multiple switches", image: "http://cdn.flaticon.com/png/256/61163.png"
            label title: "Assign a name for this virtual tile handler", required: false
            paragraph: "Assign switches to virtual tiles or real switches on next page"
        }
	}
}

def devTemplates(devType) {
    def templates = [ 
                        "base2"		:"Device with 2 switches", 
                        "base9"		:"Device with up to 9 switches", 

						"aeon4"		:"Aeon Power Strip", 

						"iPool1PSV"	:"PE653 - Pool & Spa w/o Booster (Variable speed pump)", // (blower on sw3 lights on sw2
                        "iPool1PSVB":"PE653 - Pool & Spa w/ Booster (Variable speed pump)", // (booster on sw3 lights/blower on sw2
                        
                        "iPool1"	:"PE653 - Pool and 4 Acc (1 speed pump)", 
                        "iPool1H"	:"PE653 - Pool w/Heater and 3 Acc (1 speed pump)", 
                        "iPool1PS"	:"PE653 - Pool & Spa w/o Booster (1 speed pump)", // blower on sw3 lights on sw2
                        "iPool1PSB"	:"PE653 - Pool & Spa w/ Booster (1 speed pump)", // (booster on sw3 lights/blower on sw2
                        
                        "iPool1S"	:"PE653 - Spa Only (1 speed pump)", // blower on sw3 lights on sw2
                        "iPool2S"	:"PE653 - Spa Only (2 speed pump)", // blower on sw4 lights/booster on sw3
                        
                        "iPool2"	:"PE653 - Pool and 3 Acc (2 speed pump)", 
                        "iPool2H"	:"PE653 - Pool w/Heater and 2 Acc (2 speed pump)",  
                        "iPool2PS"	:"PE653 - Pool & Spa w/o Booster  (2 speed pump)", // blower on sw3
                        "iPool2PB"	:"PE653 - Pool w/ Booster and Lights (2 speed pump)", // (booster on sw3 lights on sw4
                    ]
    if(devType) { return devTemplates.getAt(dev_type) } else { return templates }
}


def templates() {
	def templates = [
    	'aeon4': 	[ "switch":"Power Strip", "switch1":"SW Outlet 1", "switch2":"SW Outlet 2", "switch3":"SW Outlet 3", "switch4":"SW Outlet 4", "switch5":"Outlet 1", "switch6":"Outlet 2", "switch7":"All SW Outlets"],
    	'base': 	[ "switch":"switch", "switch1":"Switch 1"],
    	'base2': 	[ "switch":"switch", "switch1":"Switch 1", "switch2":"Switch 2"],
    	'base9': 	[ "switch":"switch", "switch1":"Switch 1", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Switch 5", "switch6":"Switch 6", "switch7":"Switch 7", "switch8":"Switch 8", "switch9":"Switch 9"],
    	'iPool1': 	[ "switch1":"Pool Pump", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Switch 5"],
    	'iPool1H': 	[ "switch1":"Pool Pump", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Pool Heater"],
    	'iPool1PS':	[ "switch1":"Filter Pump", "switch2":"Water Lights", "switch3":"Spa Blower", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1PSB':[ "switch1":"Filter Pump", "switch2":"Spa Blower", "switch3":"Booster Pump", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1PSV':[ "switch1":"Filter Pump", "switch2":"Spa Blower", "switch3":"Booster Pump", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1PSVB':[ "switch1":"Filter Pump", "switch2":"Pool Lights", "switch3":"Spa Blower", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool1S':	[ "switch1":"Spa Pump", "switch2":"Spa Lights", "switch3":"Spa Blower", "switch4":"Spa Accessory", "switch5":"Spa Heater"],
    	
        'iPool2': 	[ "switch1":"Pool Pump High", "switch2":"Pool Pump Low", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Switch 5"],
    	'iPool2H': 	[ "switch1":"Pool Pump High", "switch2":"Pool Pump Low", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Pool Heater"],
    	'iPool2S':	[ "switch1":"Spa Pump High", "switch2":"Spa Pump Low", "switch3":"Spa Lights", "switch4":"Spa Blower", "switch5":"Spa Heater"],
    	'iPool2PS':	[ "switch1":"Filter Pump High", "switch2":"Filter Pump Low", "switch3":"Spa Blower", "switch4":"Pool/Spa", "switch5":"Water Heater"],
    	'iPool2PB':	[ "switch1":"Pool Pump High", "switch2":"Pool Pump Low", "switch3":"Booster Pump", "switch4":"Pool Lights", "switch5":"Water Heater"],


    	'iPoolSpa':	[ "switch1":"Pump", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4", "switch5":"Pool Heater"],
        			]
    if(switch_template) { return templates.getAt(switch_template) } else { return [ "switch":"switch", "switch1":"Switch 1", "switch2":"Switch 2", "switch3":"Switch 3", "switch4":"Switch 4"] }
}


def virtualDetails() {
	unsubscribe()
	syncChildDevices()
	dynamicPage(name: "virtualDetails", title: "Which virtual switches to create for $master.label?", uninstall: true, install:true) {
        
        section {
            input "switch_template", "enum", multiple: false, required: false, refreshAfterSelection:true, options:devTemplates(), title:"Template to use", description: "What device template should to use for $master.label?", image: "http://cdn.flaticon.com/png/256/25823.png"
        }

        section {
            input "switches", "enum", multiple: true, required: false, refreshAfterSelection:true, options:templates(), title:"Select Switches", description: "Choose which switches of $master.label you would like to have as separate switches", image: "http://cdn.flaticon.com/png/256/25823.png"
        }

        section("Current Virtual Switches of $master.label:") {
            def kids = getChildDevices()
            kids.each { paragraph "$it.label" }
        }
	}
}



def installed() {
	syncChildDevices()
    def kids = getChildDevices()
}

def updated() {
	syncChildDevices()
    def kids = getChildDevices()
    unsubscribe()
	kids.each { subscribe(master, "$it.name", vswitch) }
}

def uninstalled() {
	removeChildDevices()	
}

def vswitch(evt) { 
    def vswitch = evt.descriptionText.find(/switch./).replaceAll(" ","")
//	log.debug "child switch to change: $vswitch event: $evt.value  DDNI:${ddni(vswitch)}"
    def vkid = getChildDevice(ddni(vswitch))
//    log.debug "$evt.value $evt.deviceId $evt.description $evt.descriptionText"
//    log.debug "vkid: $vkid"
	vkid."${evt.value}"()
}
    
//def mswitch(evt) { log.debug "$evt.value $evt.deviceId $evt.description $evt.descriptionText" }

def on(childDevice) {
	def num = childDevice.device.name.replaceAll("switch","")
	if(num) { master."on${num}"() } else { master.on();log.debug "No switch number provided for on" }
}

def off(childDevice) {
	def num = childDevice.device.name.replaceAll("switch","")
	if(num) { master."off${num}"() } else { master.off();log.debug "No switch number provided for off" }
}


private syncChildDevices() {    
    switches.each { def e = getChildDevice(ddni(it)); if(!e) { createChild(it) } }
    def switchKids = getChildDevices()
    def removeKids = switchKids.name - switches
//    log.debug "SWs: $switches del: $removeKids kids: $removeKids"
    removeKids.each { rem ->
    	def delKid = getChildDevice(ddni(rem))
        log.debug delKid.deviceNetworkId
        removeChildDevices(delKid)
        }
}

private createChild(vt) {
		def label = templates().getAt(vt)
		log.debug "Label $label"
		def addedvt = addChildDevice("ms_w_vts", "vTile_ms", ddni(vt), null, [name:vt, label:label, completedSetup: true])
      	log.info "created Virtual Switch ${addedvt.displayName} with DNI ${addedvt.deviceNetworkId}"
}

private removeChildDevices(delete) {
	unsubscribe()
	if(!delete) { delete = getChildDevices() }
    delete.each {
        deleteChildDevice(it.deviceNetworkId)
      	log.debug "deleted ${delete.displayName}"
    }
}

private ddni(id){
	if(!state.appId) { state.appId = app.id }
	def ddni = state.appId + "/" + id
    return ddni
}