import org.serviio.library.online.WebResourceUrlExtractor
import org.serviio.library.online.ContentURLContainer
import org.serviio.library.online.WebResourceItem
import org.serviio.library.online.PreferredQuality
import org.serviio.library.online.WebResourceContainer
import groovy.json.JsonSlurper
import org.serviio.library.metadata.MediaFileType
import org.restlet.data.Method
import org.restlet.Request
import org.restlet.Client
import org.restlet.data.Protocol
import org.restlet.Response
import org.restlet.data.Status
import org.restlet.data.ClientInfo
import sun.misc.BASE64Decoder

/**
 * WebResource extractor plugin for forum.stepashka.com
 *
 * @author Michael Mishalov
 * @version 4.0
 */
class Stepashka extends WebResourceUrlExtractor {
    final static VALID_WEB_RESOURCE_URL                     = '^(?:http?://)?(?:www\\.)?(forum.|online.)?stepashka.com/.*'
    final static WEB_RESOURCE_TITLE                         = /(?s)<h1 class=(\"btl\"|btl)>(.*?)<\/h1>/
    final static FILE_RESOURCE                              = /((?s)&amp;file=(.*?)&uid=)|((?s)&file=(.*?)")/
    final static PLAY_LIST_RESOURCE                         = /(?s)(&amp;|&)pl=(.*?)"/
    final static ST_RESOURCE                                = /(?s)value="st=(.*?)"/
    final static CHARSET_META                               = /(?s)charset=(.*?)&amp;/
    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 DEFAULT_THUMBNAIL_URL                      = "http://antoinebustros.com/blog/wp-content/uploads/2007/04/neg-film.jpg"
    final static codecA =  ["G", "d", "R", "0", "M", "Y", "4", "v", "6", "u", "t", "i", "f", "c", "s", "l", "B", "5", "n", "2", "V", "Z", "J", "m", "L", "="];
    final static codecB =  ["1", "w", "Q", "o", "9", "U", "a", "N", "x", "D", "X", "7", "z", "H", "y", "3", "e", "g", "T", "W", "b", "8", "k", "I", "p", "r"];
    protected static final int PLUGIN_VERSION = 4
    @Override
    protected WebResourceContainer extractItems(URL url, int i) {
        String pageSource = openURL(url);
        String charset = ((pageSource=~CHARSET_META)[0]-null)[-1].toString().trim()
        String webResourceTitle;
        try{
            webResourceTitle =(((pageSource =~ WEB_RESOURCE_TITLE)[0]-null)[-1]).trim()
            if(!charset.equalsIgnoreCase("Windows-1251")){
                webResourceTitle = webResourceTitle.replaceAll("с","c")
                webResourceTitle = webResourceTitle.replaceAll("С","C")
            }
        }catch (IndexOutOfBoundsException ignored){
            webResourceTitle = "Unknown title"
        }
        def videoResources = pageSource =~ FILE_RESOURCE
        List<WebResourceItem> items = []
        if (videoResources.size() > 0){
            items << new WebResourceItem(title: webResourceTitle, additionalInfo: ['link' :decrypt(((String)(videoResources[0]-null)[-1]).trim())])
        }else{
            String encodedPL;
            videoResources = pageSource =~ PLAY_LIST_RESOURCE
            if(videoResources.size()>0){
                encodedPL = openURL(new URL(decrypt(videoResources[0][-1].toString().trim())), USER_AGENT).trim();
            }else{
                videoResources = pageSource =~ ST_RESOURCE
                assert videoResources.size() > 0
                encodedPL = openURL(new URL(videoResources[0][-1].toString().trim()), USER_AGENT).trim();
            }
            def slurper = new JsonSlurper()
            String json = decrypt(encodedPL);
            json = prepareJson(json)
            def playlist = slurper.parseText(json)
            if(playlist.pl){
                json=playlist.pl
                json = prepareJson(json)
                playlist = slurper.parseText(json)
            }
            items.addAll(fetchItems(playlist))
        }
        return new WebResourceContainer(title: webResourceTitle, thumbnailUrl: DEFAULT_THUMBNAIL_URL, items: items)
    }

    private String prepareJson(String json) {
        if (!json.startsWith("{")) {
            int index = json.indexOf("{");
            assert index > 0
            json = json.substring(index);
        }
        if(json.startsWith("{'")){
            json = json.replace("'","\"")
        }
        json
    }

    private String openURL(URL url, int callNumber=0){
        String pageSource = null;
        if (url==null || callNumber >10) {
            return pageSource;
        }
        Request request = new Request(Method.GET, url.toString());
        Client client = new Client(Protocol.HTTP);
        ClientInfo info = new ClientInfo();
        info.setAgent(USER_AGENT);
        request.setClientInfo(info);
        Response response = client.handle(request);
        Status status = response.getStatus();
        if(Status.SUCCESS_OK.equals(status)){
            pageSource = response.getEntityAsText()
        }else if ( Status.REDIRECTION_PERMANENT.equals(response.getStatus()) ||
                   Status.REDIRECTION_TEMPORARY.equals(response.getStatus()) ||
                   Status.REDIRECTION_FOUND.equals(response.getStatus())){
            pageSource = openURL(response.getLocationRef().toUrl(),++callNumber);
        }
        return pageSource;
    }
    /**
     * Finds all actual video links and titles in received data
     * @param data to search
     * @return List contains all founded items
     */
    private List<WebResourceItem> fetchItems(data){
        List<WebResourceItem> items = [];
        if(data in HashMap){
            def playlist = data.playlist 
            if(playlist){
               items.addAll(fetchItems(playlist))
            }else{
                String link = data.file;
                String title = data.comment;
                items << new WebResourceItem(title: title, additionalInfo: ['link' :link])
            }
        }else if (data in ArrayList){
            data.each{
                items.addAll(fetchItems(it))
            }
        }
        return items;
    }
    @Override
    protected ContentURLContainer extractUrl(WebResourceItem webResourceItem, PreferredQuality preferredQuality) {
        log("Extracting:"+ webResourceItem.additionalInfo.link)
        return new ContentURLContainer(fileType: MediaFileType.VIDEO, contentUrl: webResourceItem.additionalInfo.link)
    }
    private static String  decrypt(String input) {
        String output = input;
        for(int i = 0; i<codecA.size();i++){
            output = swap(codecB[i],codecA[i],output);
        }
        BASE64Decoder decoder = new BASE64Decoder();
        output = new String(decoder.decodeBuffer(output),"UTF8");
        return output;
    }
    private static String swap(String first, String second, String input) {
        String output = input.replace(first, "___");
        output = output.replace(second, first);
        output = output.replace("___", second);
        return output;
    }

    @Override
    boolean extractorMatches(URL url) {
        return url ==~ VALID_WEB_RESOURCE_URL
    }

    @Override
    String getExtractorName() {
        return getClass().getName()
    }

    @Override
    int getVersion() {
        return PLUGIN_VERSION;
    }
    static void main(args) {
        //def TestUrl = new URL("http://online.stepashka.com/eng-serialy/3350-spartak-bogi-areny-spartacus-gods-of-the-arena-2011.html")
        //def TestUrl = new URL("http://online.stepashka.com/god-2013/25478-mat-i-macheha-serial-2013.html")
        //def TestUrl = new URL("http://online.stepashka.com/serialy/eng-serialy/24497-vikingi-vikings-2013.html")
        def TestUrl = new URL("http://online.stepashka.com/serialy/eng-serialy/3212-igra-prestolov-game-of-thrones-2011.html")
        //def TestUrl = new URL("http://online.stepashka.com/serialy/dramy_s/31346-drevnie-the-originals-serial-2013.html")
        Stepashka extractor = new Stepashka()
        println "PluginName               : " + extractor.getExtractorName();
        println "TestMatch                : " + extractor.extractorMatches(TestUrl);
        WebResourceContainer container = extractor.extractItems(TestUrl, -1);
        container.getItems().each {
            println it.title + ", URL                  : " + extractor.extractUrl(it, PreferredQuality.HIGH).contentUrl;it.title
        }

    }
}
