import java.util.concurrent.Callable
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.Future

import org.serviio.library.online.*

/**
 * WebResource extractor Serviio plugin for RedTube.com <br/>
 * <b>version</b> 3.0
 *
 * @author Michael Mishalov
 * @since JDK 1.6, Groovy 1.8.6, Serviio 1.1
 */
class RedTube extends WebResourceUrlExtractor{
    ////////////////////////////////////////////[Constants]////////////////////////////////////////////
    final static VALID_WEB_RESOURCE_URL                    = '^(?:http?://)?(?:www\\.)?redtube.com.*'
    final static DEFAULT_VIDEO_DOMAIN                      = "http://redtube.com"
    final static USER_AGENT                                = 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1'
    final static VIDEO_DIV_REGEX                           = /(?s)<div class="video">(.*?)<\/div>/
    final static VIDEO_THUMBNAIL_REGEX                     = /(?s)src="(.*?)" /
    final static VIDEO_PAGE_URL_REGEX                      = /(?s)<a href="(.*?)" /
    final static VIDEO_PAGE_TITLE_REGEX                    = /(?s)title="(.*?)" /
    final static VIDEO_STREAM_H264_REGEX                   = /(?s)flv_h264_url=(.*?)&/
    final static VIDEO_STREAM_MP4_REGEX                    = /(?s)mp4_url=(.*?)&/
    final static PAGE_PARAMETER                            = "?page="
    final static FROM_PARAMETER                            = "from"
    final static TO_PARAMETER                              = "to"
    final static FORMAT_PARAMETER                          = "format"
    final static SUPPORTED_CODECS                          = ["h264":VIDEO_STREAM_H264_REGEX,"mp4":VIDEO_STREAM_MP4_REGEX];

    /////////////////////////////////////////////[Methods]/////////////////////////////////////////////
    @Override
    protected WebResourceContainer extractItems(URL url, int i) {
        return new WebResourceContainer(title: url.toString(), items: reprieveURLs(url))
    }
    List<WebResourceItem> reprieveURLs(URL url) {
        String codec;
        List<URL> pagesToProcess;
        (pagesToProcess,codec)= generatePages(url)
        List<WebResourceItem> allItems = [];
        List<Future<List>> futures = [];
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        pagesToProcess.each {
            futures << executorService.submit(new Callable<List>(){
                            @Override
                            List call() {
                                String pageSource = openURL(it, USER_AGENT)
                                List<WebResourceItem> pageItems = []
                                String divContent;
                                (pageSource=~VIDEO_DIV_REGEX).each {
                                    divContent = (it-null)[-1];
                                    Map<String,String> additionalInfo = new HashMap<String, String>();
                                    additionalInfo.put("videoPageURL",DEFAULT_VIDEO_DOMAIN + ((divContent=~VIDEO_PAGE_URL_REGEX)[0]-null)[-1].toString().trim())
                                    additionalInfo.put("thumbnailURL",((divContent=~VIDEO_THUMBNAIL_REGEX)[0]-null)[-1].toString().trim())
                                    additionalInfo.put("codec",codec);
                                    String title =((divContent=~VIDEO_PAGE_TITLE_REGEX)[0]-null)[-1].toString().trim()
                                    pageItems << new WebResourceItem(title: title, additionalInfo: additionalInfo)
                                }
                                return pageItems;
                            }
                        });
        }
        executorService.shutdown();
        futures.each {allItems.addAll(it.get())}
        return allItems;
    }

    def private generatePages(URL url) {
        List<URL> pagesToProcess = [];
        def params = url.query!=null? url.query.split(" ").inject([:]){
            params,
            param-> if(param.contains("=")){
                def (key, value) = param.split('=').toList();
                params[key] = value;
            }
            params
        }:[:];
        if (params[FROM_PARAMETER]!=null && params[TO_PARAMETER]!=null) {
            for (i in (params[FROM_PARAMETER] as int)..(params[TO_PARAMETER] as int)) {
                pagesToProcess << new URL(url.protocol+"://"+ url.host + url.path + PAGE_PARAMETER + i);
            }
        } else {
            pagesToProcess << url;
        }
        String codec = (params[FORMAT_PARAMETER]!=null)? params[FORMAT_PARAMETER]:"h264";
        return [pagesToProcess,codec];
    }

    @Override
    protected ContentURLContainer extractUrl(WebResourceItem webResourceItem, PreferredQuality preferredQuality) {
        if(log.isDebugEnabled()){
            log(String.format("Staring video URL extraction for %s",webResourceItem.getAdditionalInfo().get("videoPageURL")))
        }
        try{
            ContentURLContainer contentURLContainer = new ContentURLContainer();
            String pageSource = openURL( new URL(webResourceItem.getAdditionalInfo().get("videoPageURL")), USER_AGENT)
            contentURLContainer.setThumbnailUrl(webResourceItem.getAdditionalInfo().get("thumbnailURL"))
            contentURLContainer.setContentUrl(new URLDecoder().decode((String)(((pageSource=~SUPPORTED_CODECS[webResourceItem.additionalInfo.get("codec")])[0]-null)[-1]),"UTF-8").trim())
            return contentURLContainer
        }catch (IndexOutOfBoundsException e){
            log.error(String.format("%s , Filed to create resource item for URL: %s",getExtractorName(), webResourceItem.getAdditionalInfo().get("videoPageURL")), log.isDebugEnabled()? e:null)
        }
        return null
    }
    @Override
    boolean extractorMatches(URL url) {
        return url ==~ VALID_WEB_RESOURCE_URL
    }

    @Override
    String getExtractorName() {
        return getClass().getName()
    }

    @Override
    int getVersion() {
        return 3
    }

    static void main(args) {
        def TestUrl = new URL("http://www.redtube.com/redtube/gangbang?page=5 format=h264")
        RedTube extractor = new RedTube()
        WebResourceContainer container = extractor.extractItems(TestUrl, -1);
        println "PluginName               : " + extractor.getExtractorName();
        println "TestMatch                : " + extractor.extractorMatches(TestUrl);
        container.getItems().each {
            println "URL                  : " + extractor.extractUrl(it, PreferredQuality.HIGH)
        }
    }
}
