//
//  RokuTransportService.swift
//
//  Copyright (c) 2015 David Robles
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//  SOFTWARE.

import Foundation

open class RokuTransportService: AbstractUPnPService {
    
    /*
    public func setAVTransportURI(instanceID instanceID: String, currentURI: String, currentURIMetadata: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = [
            "InstanceID" : instanceID,
            "CurrentURI" : currentURI,
            "CurrentURIMetaData": currentURIMetadata]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "SetAVTransportURI", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            success()
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func setNextAVTransportURI(instanceID instanceID: String, nextURI: String, nextURIMetadata: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = [
            "InstanceID" : instanceID,
            "NextURI" : nextURI,
            "NextURIMetaData": nextURIMetadata]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "SetNextAVTransportURI", serviceURN: urn, arguments: arguments)
        
        // Check if the optional SOAP action "SetNextAVTransportURI" is supported
        supportsSOAPAction(actionParameters: parameters) { (isSupported) -> Void in
            if isSupported {
                self.soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
                    success()
                    }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                        failure(error as NSError)
                })
            } else {
                failure(error: createError("SOAP action '\(parameters.soapAction)' unsupported by service \(self.urn) on device \(self.device?.friendlyName)"))
            }
        }
    }
    
    public func getMediaInfo(instanceID instanceID: String, success: (numberOfTracks: Int, mediaDuration: String?, currentURI: String?, currentURIMetaData: String?, nextURI: String?, nextURIMetaData: String?, playMedium: String?, recordMedium: String?, writeStatus: String?) -> Void, failure: (error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "GetMediaInfo", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            let responseObject = responseObject as? [String: String]
            var numberOfTracks: Int?
            if let numberOfTracksString = responseObject?["NrTracks"] {
                numberOfTracks = Int(numberOfTracksString)
            }
            
            success(numberOfTracks: numberOfTracks ?? 0, mediaDuration: responseObject?["MediaDuration"], currentURI: responseObject?["CurrentURI"], currentURIMetaData: responseObject?["CurrentURIMetaData"], nextURI: responseObject?["NextURI"], nextURIMetaData: responseObject?["NextURIMetaData"], playMedium: responseObject?["PlayMedium"], recordMedium: responseObject?["RecordMedium"], writeStatus: responseObject?["WriteStatus"])
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func getTransportInfo(instanceID instanceID: String, success: (currentTransportState: String?, currentTransportStatus: String?, currentSpeed: String?) -> Void, failure: (error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "GetTransportInfo", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            let responseObject = responseObject as? [String: String]
            success(currentTransportState: responseObject?["CurrentTransportState"], currentTransportStatus: responseObject?["CurrentTransportStatus"], currentSpeed: responseObject?["CurrentSpeed"])
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func getPositionInfo(instanceID instanceID: String, success: (track: String?, trackDuration: String?, trackMetaData: String?, trackURI: String?, relativeTime: String?, absoluteTime: String?, relativeCount: String?, absoluteCount: String?) -> Void, failure: (error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "GetPositionInfo", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            let responseObject = responseObject as? [String: String]
            success(track: responseObject?["Track"], trackDuration: responseObject?["TrackDuration"], trackMetaData: responseObject?["TrackMetaData"], trackURI: responseObject?["TrackURI"], relativeTime: responseObject?["RelTime"], absoluteTime: responseObject?["AbsTime"], relativeCount: responseObject?["RelCount"], absoluteCount: responseObject?["AbsCount"])
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func getDeviceCapabilities(instanceID instanceID: String, success: (playMedia: String?, recordMedia: String?, recordQualityModes: String?) -> Void, failure: (error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "GetDeviceCapabilities", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            let responseObject = responseObject as? [String: String]
            success(playMedia: responseObject?["PlayMedia"], recordMedia: responseObject?["RecMedia"], recordQualityModes: responseObject?["RecQualityModes"])
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func getTransportSettings(instanceID instanceID: String, success: (playMode: String?, recordQualityMode: String?) -> Void, failure: (error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "GetTransportSettings", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            let responseObject = responseObject as? [String: String]
            success(playMode: responseObject?["PlayMode"], recordQualityMode: responseObject?["RecQualityMode"])
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func stop(instanceID instanceID: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Stop", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            success()
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func play(instanceID instanceID: String, speed: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = [
            "InstanceID" : instanceID,
            "Speed" : speed]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Play", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in            
            success()
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func pause(instanceID instanceID: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Pause", serviceURN: urn, arguments: arguments)
        
        // Check if the optional SOAP action "Pause" is supported
        supportsSOAPAction(actionParameters: parameters) { (isSupported) -> Void in
            if isSupported {
                self.soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
                    success()
                    }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                        failure(error as NSError)
                })
            } else {
                failure(error: createError("SOAP action '\(parameters.soapAction)' unsupported by service \(self.urn) on device \(self.device?.friendlyName)"))
            }
        }
    }

    public func record(instanceID instanceID: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Record", serviceURN: urn, arguments: arguments)
        
        // Check if the optional SOAP action "Record" is supported
        supportsSOAPAction(actionParameters: parameters) { (isSupported) -> Void in
            if isSupported {
                self.soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
                    success()
                    }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                        failure(error as NSError)
                })
            } else {
                failure(error: createError("SOAP action '\(parameters.soapAction)' unsupported by service \(self.urn) on device \(self.device?.friendlyName)"))
            }
        }
    }
    
    public func seek(instanceID instanceID: String, unit: String, target: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = [
            "InstanceID" : instanceID,
            "Unit" : unit,
            "Target" : target]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Seek", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            success()
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func next(instanceID instanceID: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Next", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            success()
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func previous(instanceID instanceID: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "Previous", serviceURN: urn, arguments: arguments)
        
        soapSessionManager.POST(controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
            success()
            }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                failure(error as NSError)
        })
    }
    
    public func setPlayMode(instanceID instanceID: String, newPlayMode: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = [
            "InstanceID" : instanceID,
            "NewPlayMode" : newPlayMode]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "SetPlayMode", serviceURN: urn, arguments: arguments)
        
        // Check if the optional SOAP action "SetPlayMode" is supported
        supportsSOAPAction(actionParameters: parameters) { (isSupported) -> Void in
            if isSupported {
                self.soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
                    success()
                    }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                        failure(error as NSError)
                })
            } else {
                failure(error: createError("SOAP action '\(parameters.soapAction)' unsupported by service \(self.urn) on device \(self.device?.friendlyName)"))
            }
        }
    }
    
    public func setRecordQualityMode(instanceID instanceID: String, newPlayMode: String, success: () -> Void, failure:(error: NSError) -> Void) {
        let arguments = [
            "InstanceID" : instanceID,
            "NewRecordQualityMode" : newPlayMode]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "SetRecordQualityMode", serviceURN: urn, arguments: arguments)
        
        // Check if the optional SOAP action "SetRecordQualityMode" is supported
        supportsSOAPAction(actionParameters: parameters) { (isSupported) -> Void in
            if isSupported {
                self.soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
                    success()
                    }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                        failure(error as NSError)
                })
            } else {
                failure(error: createError("SOAP action '\(parameters.soapAction)' unsupported by service \(self.urn) on device \(self.device?.friendlyName)"))
            }
        }
    }
    
    public func getCurrentTransportActions(instanceID instanceID: String, success: (actions: String?) -> Void, failure:(error: NSError) -> Void) {
        let arguments = ["InstanceID" : instanceID]
        
        let parameters = SOAPRequestSerializer.Parameters(soapAction: "GetCurrentTransportActions", serviceURN: urn, arguments: arguments)
        
        // Check if the optional SOAP action "GetCurrentTransportActions" is supported
        supportsSOAPAction(actionParameters: parameters) { (isSupported) -> Void in
            if isSupported {
                self.soapSessionManager.POST(self.controlURL.absoluteString!, parameters: parameters, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) -> Void in
                    let responseObject = responseObject as? [String: String]
                    success(actions: responseObject?["Actions"])
                    }, failure: { (task: NSURLSessionDataTask?, error: NSError) -> Void in
                        failure(error as NSError)
                })
            } else {
                failure(error: createError("SOAP action '\(parameters.soapAction)' unsupported by service \(self.urn) on device \(self.device?.friendlyName)"))
            }
        }
    }

    override public func createEvent(eventXML: NSData) -> UPnPEvent {
        return AVTransport1Event(eventXML: eventXML, service: self)
    }
     */
}

/// for objective-c type checking
extension AbstractUPnP {
    public func isRokuTransportService() -> Bool {
        return self is RokuTransportService
    }
}

/// overrides ExtendedPrintable protocol implementation
extension RokuTransportService {
    override public var className: String { return "\(type(of: self))" }
    override open var description: String {
        var properties = PropertyPrinter()
        properties.add(super.className, property: super.description)
        return properties.description
    }
}
