import org.serviio.library.metadata.*
import org.serviio.library.online.*

/**
 * WebResource extractor plugin for player.canalplus.fr
 *
 * @author Illico
 * @version 1.2
 *
 */
class CanalPlus extends WebResourceUrlExtractor {

	final int VERSION = 12
	final int MAXCPLUSITEM = 30
	final VALID_FEED_URL = '(^http://player.canalplus.fr/#/\\d*{6}$)||(^http://player.canalplus.fr/#/.*/.*$)'
	final BASE_URL = "http://webservice.canal-plus.com/rest/bigplayer/"
	final THEME_REGEX = '^http://player.canalplus.fr/#/(.*?)/(.*?)$'

	String getExtractorName() {
		return getClass().getName()
	}

	int getVersion() {
		return VERSION
	}

	boolean extractorMatches(URL feedUrl) {
		return feedUrl ==~ VALID_FEED_URL
	}

	WebResourceContainer extractItems(URL resourceUrl, int maxItems) {
		try {
			String WebResourceTitle = "CANAL PLUS PLAYER"
			String WebResourceThumbnailUrl = "http://www.news-hightech.com/wp-content/uploads/2011/10/canalplus.jpg"
			// Extract Url informations
			def ThemeMatcher = resourceUrl.toString() =~ THEME_REGEX
			//assert ThemeMatcher.getCount() > 0, "Error : Url format http://player.canalplus.fr/#/(Thematique)/(Selection)"
			String ThemeSelected     = ThemeMatcher[0][1].toUpperCase();                     loginfo("ThemeSelected     : "+ThemeSelected);
			String SelectionSelected = ThemeMatcher[0][2].replaceAll("-"," ").toUpperCase(); loginfo("SelectionSelected : "+SelectionSelected);
			// GET the selected SELECTION
			def Selection = getSelection(SelectionSelected);
			List<WebResourceItem> items = []
			if (Selection[0] == null) {
				// Extract Items from search request
				items = ExtractItemsFromSearch(SelectionSelected,MAXCPLUSITEM)
			} else {
				// Extract Items from selected Selection ID
				items = ExtractItemsFromID(Selection[0].ID.text(),MAXCPLUSITEM)
			}
			return new WebResourceContainer(title: WebResourceTitle, thumbnailUrl: WebResourceThumbnailUrl, items: items)
		} catch (Exception e) {
			loginfo("Extract Items of "+resourceUrl+" failed");
			return null;
		}
	}

	private def getSelection(String SelectionSelected){
		//Return the selected SELECTION
		try {
			// GET INIT PLAYER Xml
			def PlayerXml = new XmlParser().parse(BASE_URL + "initPlayer/")
			//assert PlayerXml.name() == "INIT_PLAYER", "Error : Could not parse Init Page"
			def Thematiques = PlayerXml.THEMATIQUES.THEMATIQUE
			def Selection = []
			for( int i = 0; i < Thematiques.size(); i++ ) {
				def Selections = Thematiques[i].SELECTIONS.SELECTION
				for( int j = 0; j < Selections.size(); j++ ) {
					def text = Selections[j].NOM.text().replaceAll("é","e").replaceAll("è","e").replaceAll("à","a").toUpperCase()
					if (text == SelectionSelected) {
						Selection.addAll(Selections[j])
					}
				}
			}
			loginfo("Selection found:"+ Selection.size())
			return Selection
		} catch (Exception e) {
			loginfo("Extract "+SelectionSelected+" selection failed");
			return null;
		}
	}

	private def ExtractItemsFromSearch(String SelectionSelected, int maxItems){
		//Return the items from search request
		try {
			List<WebResourceItem> items = []
			def MozaicXml = new XmlParser().parse("http://service.canal-plus.com/video/rest/search/cplus/"+SelectionSelected)
			loginfo("Search Items found: " + MozaicXml.VIDEO.size()+" only $MAXCPLUSITEM items will be extracted")
			def ItemsAdded = 0;
			for( int i = 0; i < MozaicXml.VIDEO.size() && (maxItems == -1 || ItemsAdded < maxItems) ; i++ ) {
				String WebResourceItemTitle        = MozaicXml.VIDEO[i].INFOS.TITRAGE.TITRE.text()+" - "+MozaicXml.VIDEO[i].INFOS.TITRAGE.SOUS_TITRE.text()
				String WebResourceItemThumbnailUrl = MozaicXml.VIDEO[i].MEDIA.IMAGES.GRAND.text()
				String WebResourceItemUrl_LOW      = MozaicXml.VIDEO[i].MEDIA.VIDEOS.BAS_DEBIT.text()
				String WebResourceItemUrl_MEDIUM   = MozaicXml.VIDEO[i].MEDIA.VIDEOS.HAUT_DEBIT.text()
				String WebResourceItemUrl_HIGH     = MozaicXml.VIDEO[i].MEDIA.VIDEOS.HD.text()
				String WebResourceItemInfoUrl      = MozaicXml.VIDEO[i].URL.text()
				WebResourceItem item = new WebResourceItem(title: WebResourceItemTitle,
				additionalInfo: [	'WebResourceItemThumbnailUrl': WebResourceItemThumbnailUrl,
					'WebResourceItemUrl_LOW'     : WebResourceItemUrl_LOW,
					'WebResourceItemUrl_MEDIUM'  : WebResourceItemUrl_MEDIUM,
					'WebResourceItemUrl_HIGH'    : WebResourceItemUrl_HIGH,
					'WebResourceItemInfoUrl'     : WebResourceItemInfoUrl])
				loginfo(WebResourceItemTitle)
				items << item
				ItemsAdded++
			}
			return items;
		} catch (Exception e) {
			loginfo("Extract "+SelectionSelected+" from search request failed");
			return null;
		}
	}

	private def ExtractItemsFromID(String IDSelected, int maxItems){
		//Return the items from ID request
		try {
			List<WebResourceItem> items = []
			// GET MOZAIC PAGE
			def MozaicXml = new XmlParser().parse(BASE_URL + "getMEAs/"+IDSelected)
			//assert MozaicXml.name() == "MEAS", "Error : Could not parse Mozaic Page"
			// Extract Mozaic Video resources
			def ItemsAdded = 0;
			loginfo("Selected Video found : "+MozaicXml.MEA.size()+" only $MAXCPLUSITEM items will be extracted")
			for( int i = 0; i < MozaicXml.MEA.size() && (maxItems == -1 || ItemsAdded < maxItems) ; i++ ) {
				String WebResourceItemTitle        = MozaicXml.MEA[i].INFOS.TITRAGE.TITRE.text()+" - "+MozaicXml.MEA[i].INFOS.TITRAGE.SOUS_TITRE.text()
				String WebResourceItemThumbnailUrl = MozaicXml.MEA[i].MEDIA.IMAGES.GRAND.text()
				String WebResourceItemId           = MozaicXml.MEA[i].ID.text()
				// Extract Videos Url
				loginfo(WebResourceItemId+"-"+WebResourceItemTitle)
				def VideosXml = new XmlParser().parse(BASE_URL + "getVideosLiees/"+ WebResourceItemId)
				//assert VideosXml.name() == "VIDEOS"
				def VideoSelected = VideosXml.VIDEO.findAll{ it.ID.text() == WebResourceItemId }
				//assert VideoSelected != null, "La Video "+WebResourceItemId+" choisi n'existe pas dans le catalogue"
				String WebResourceItemUrl_LOW      = VideoSelected[0].MEDIA.VIDEOS.BAS_DEBIT.text()
				String WebResourceItemUrl_MEDIUM   = VideoSelected[0].MEDIA.VIDEOS.HAUT_DEBIT.text()
				String WebResourceItemUrl_HIGH     = VideoSelected[0].MEDIA.VIDEOS.HD.text()
				String WebResourceItemInfoUrl      = VideoSelected[0].URL.text()
				WebResourceItem item = new WebResourceItem(title: WebResourceItemTitle,
				additionalInfo: [	'WebResourceItemThumbnailUrl': WebResourceItemThumbnailUrl,
					'WebResourceItemUrl_LOW'     : WebResourceItemUrl_LOW,
					'WebResourceItemUrl_MEDIUM'  : WebResourceItemUrl_MEDIUM,
					'WebResourceItemUrl_HIGH'    : WebResourceItemUrl_HIGH,
					'WebResourceItemInfoUrl'     : WebResourceItemInfoUrl])
				items << item
				ItemsAdded++
			}
			return items;
		} catch (Exception e) {
			loginfo("Extract "+IDSelected+" from search request failed");
			return null;
		}
	}

	ContentURLContainer extractUrl(WebResourceItem item, PreferredQuality requestedQuality) {
		String ItemVideoUrl
		switch (requestedQuality) {
			case "LOW"    	: ItemVideoUrl = item.getAdditionalInfo()['WebResourceItemUrl_LOW'];break;
			case "MEDIUM" 	: ItemVideoUrl = item.getAdditionalInfo()['WebResourceItemUrl_MEDIUM'];break;
			case "HIGH"   	: ItemVideoUrl = item.getAdditionalInfo()['WebResourceItemUrl_HIGH'];break;
			default			: ItemVideoUrl = item.getAdditionalInfo()['WebResourceItemUrl_HIGH'];break;
		}
		String contentUrl
		if (ItemVideoUrl.startsWith('http:')) {
			contentUrl = ItemVideoUrl
			//loginfo(" contentUrl(http): "+contentUrl)
		} else {
			def VideoUrlMatcher = ItemVideoUrl =~ '(rtmp.*://.*?)/(.*?/.*?)/(.*)'
			assert VideoUrlMatcher.getCount() > 0, "Le lien de la video n'est pas supporté "+ItemVideoUrl
			if ( VideoUrlMatcher[0][3].endsWith('.mp4') ) {
				contentUrl = VideoUrlMatcher[0][1]+":80/"+VideoUrlMatcher[0][2]+" app="+VideoUrlMatcher[0][2]+" playpath=mp4:"+VideoUrlMatcher[0][3]+" swfVfy=1"
				//loginfo(" contentUrl(mp4): "+contentUrl)
			}else{
				contentUrl = VideoUrlMatcher[0][1]+":80/"+VideoUrlMatcher[0][2]+" app="+VideoUrlMatcher[0][2]+" playpath="+VideoUrlMatcher[0][3]+" swfVfy=1"
				//loginfo(" contentUrl(flv): "+contentUrl)
			}
		}
		return new ContentURLContainer(fileType: MediaFileType.VIDEO, contentUrl: contentUrl, thumbnailUrl: item.getAdditionalInfo()['WebResourceItemThumbnailUrl'])
	}

	private String loginfo(String text) {
		log(text);
		println(text);
	}

	static WebResourceContainer testURL(String url, int itemCount = 2) {
		CanalPlus extractor = new CanalPlus();
		URL resourceUrl = new URL(url);
		println "getExtractorName : " + extractor.getExtractorName();
		println "getVersion : " + extractor.getVersion();
		assert extractor.extractorMatches(resourceUrl), 'Url doesn\'t match for this WebResource plugin'
		println "extractorMatches : " + extractor.extractorMatches(resourceUrl);
		WebResourceContainer container = extractor.extractItems(resourceUrl, itemCount);
		assert container != null, 'Container is empty'
		assert container.items != null, 'Container contains no items'
		//assert container.items.size() == itemCount, 'Amount of items is invalid. Expected was ' + itemCount + ', result was ' + container.items.size()
		println "extractItems : " + container.items.size()
		println "***** HIGH *****";extractor.extractUrl(container.getItems()[1], PreferredQuality.HIGH);
		//println "**** MEDIUM ****";extractor.extractUrl(container.getItems()[1], PreferredQuality.MEDIUM);
		//println "***** LOW ******";extractor.extractUrl(container.getItems()[1], PreferredQuality.LOW);
		return container
	}

	static void main(args) {
		testURL("http://player.canalplus.fr/#/emissions/le-grand-journal",-1)
		// testURL("http://player.canalplus.fr/#/cinema/les-dernieres-ba",-1)
		testURL("http://player.canalplus.fr/#/search/zapping",-1)
		// testURL("http://player.canalplus.fr/#/search/le%20petit%20journal",-1)
	}
}