import groovy.json.JsonSlurper
import org.restlet.data.CookieSetting
import org.restlet.engine.util.CookieSettingSeries
import org.restlet.util.Series
import org.serviio.library.metadata.MediaFileType
import org.serviio.library.online.*
import sun.misc.BASE64Decoder

import javax.script.ScriptEngine
import javax.script.ScriptEngineManager

/**
 * WebResource extractor plugin for SeasonVar.ru
 *
 * @author Georgy Baydjanov, Michael Mishalov
 * @version 2.0
 */
class SeasonVar extends WebResourceUrlExtractor {
    final static VALID_WEB_RESOURCE_URL                        = '^(?:http?://)?(?:www\\.)?seasonvar.ru/.*'
    final static JS_SOURCE_REGEX                               =/(?s)eval(.*?)<\/script>/
    final static PLAYLIST_REGEX                                =/(?s)pl":"(.*?)",/
    final static TITLE_REGEX                                   = /(?s)<title>(.*?)<\/title>/
    final static USER_AGENT                                    = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0'
    final static DEFAULT_THUMBNAIL_URL                         = "http://pixabay.com/static/uploads/photo/2012/04/11/13/24/video-28212_640.png"
    final static codecsMatrix = [codecA:[["b", "U", "N", "I", "Z", "o", "H", "V", "T", "w", "W", "D", "a", "f", "t", "Q", "9", "v", "g", "8", "x", "0", "1", "4", "c", "="],
                                         ["5", "L", "i", "f", "B", "v", "D", "Q", "9", "T", "a", "V", "o", "Y", "w", "J", "7", "M", "Z", "c", "d", "g", "y", "e", "u", "="],
                                         ["Z", "8", "i", "t", "b", "M", "U", "9", "z", "Y", "1", "s", "7", "c", "R", "J", "I", "l", "G", "a", "m", "k", "f", "4", "6", "="],
                                         ["g", "N", "8", "z", "a", "o", "3", "W", "x", "7", "2", "L", "t", "Q", "v", "e", "l", "w", "U", "5", "m", "s", "V", "D", "Y", "="],
                                         ["0", "t", "a", "d", "7", "J", "B", "H", "x", "Q", "y", "Z", "5", "I", "1", "v", "g", "b", "M", "z", "N", "L", "R", "c", "w", "="],
                                         ["W", "a", "u", "V", "d", "M", "8", "6", "7", "i", "H", "Y", "9", "5", "N", "s", "w", "D", "p", "l", "T", "Z", "x", "G", "m", "="],
                                         ["J", "p", "v", "n", "s", "R", "0", "3", "T", "m", "w", "u", "9", "x", "g", "a", "G", "L", "U", "X", "z", "t", "b", "7", "H", "="]],  /*new*/
                                 codecB:[["p", "z", "m", "X", "R", "J", "2", "Y", "d", "n", "B", "G", "u", "y", "L", "s", "l", "M", "i", "e", "6", "k", "7", "3", "5", "F"],
                                         ["s", "p", "6", "3", "N", "G", "8", "k", "0", "U", "t", "z", "H", "l", "x", "W", "m", "n", "R", "I", "2", "b", "X", "1", "4", "E"],
                                         ["d", "X", "x", "n", "2", "3", "v", "5", "L", "u", "D", "g", "H", "N", "W", "y", "w", "V", "B", "e", "o", "Q", "p", "0", "T", "O"],
                                         ["9", "1", "4", "Z", "I", "M", "6", "i", "X", "J", "d", "f", "T", "u", "G", "n", "y", "B", "c", "k", "R", "b", "p", "0", "H", "C"],
                                         ["u", "U", "f", "T", "k", "W", "X", "4", "8", "2", "9", "Y", "o", "D", "e", "n", "l", "s", "3", "G", "V", "p", "i", "m", "6", "F"],
                                         ["2", "B", "g", "v", "Q", "n", "z", "b", "3", "f", "y", "1", "J", "I", "k", "X", "0", "e", "L", "c", "R", "4", "o", "t", "U", "O"],
                                         ["f", "N", "W", "5", "e", "l", "V", "D", "y", "Z", "I", "i", "M", "o", "Q", "1", "B", "8", "2", "6", "c", "d", "4", "Y", "k", "C"]]] /*new*/

	
    @Override
    protected WebResourceContainer extractItems(URL url, int i) {
        List<WebResourceItem> items = []
        Series<CookieSetting> settings = new CookieSettingSeries();
        String pageSource = openURL(url, USER_AGENT,settings);
        String jsSource = ((pageSource=~JS_SOURCE_REGEX)[0]-null)[-1].toString().trim();
        jsSource = jsSource.substring(1,jsSource.length()-1);
        jsSource = "jsSource ="+jsSource;
        ScriptEngineManager manager = new ScriptEngineManager()
        ScriptEngine engine = manager.getEngineByName("JavaScript")
        engine.eval(jsSource);
        jsSource = engine.get("jsSource");
        String playlistURL = decrypt(((jsSource=~PLAYLIST_REGEX)[0]-null)[-1].toString().trim());
        assert (playlistURL!=null);
        String title= ((pageSource=~TITLE_REGEX)[0]-null)[-1].toString().trim();
        title= title.substring(0,title.indexOf(" смотреть онлайн"));
        title = title.replaceAll("с","c");
        title = title.replaceAll("С","C");
        title = new String(title.getBytes(),"UTF-8");
        String encryptedJson = openURL(new URL("http://seasonvar.ru"+playlistURL), USER_AGENT,settings);
        String json = decrypt(encryptedJson);
        def slurper = new JsonSlurper();
        def playlist = slurper.parseText(json) ;
        items.addAll(fetchItems(playlist)) ;
        return new WebResourceContainer(title:title, thumbnailUrl: DEFAULT_THUMBNAIL_URL, items: items)
    }

    /**
     * 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;
                title=title.replaceAll("\\r\\n|\\r|\\n", " ");
                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) {
        return new ContentURLContainer(fileType: MediaFileType.VIDEO, contentUrl: webResourceItem.additionalInfo.link);
    }
    private  String decrypt(String input){
        def codecPairs = [codecsMatrix.codecA, codecsMatrix.codecB].transpose();
        for(def pair: codecPairs){
            String output = decrypt(input,(ArrayList<String>)pair[0],(ArrayList<String>)pair[1]);
            if(output.endsWith(".xml")|| output.endsWith("}")) return output;
        }
        return null;
    }
    private String decrypt(String input,ArrayList<String> codecA, ArrayList<String> codecB) {
        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 String swap(String first, String second, String input) {
        String output = input.replace(first, "___");
        output = output.replace(second, first);
        output = output.replace("___", second);
        return output;
    }

    protected String openURL(URL url, String userAgent,Series<CookieSetting> cookieSettings){
        URLConnection conn  = url.openConnection();
        conn.setRequestProperty("Cookie","sva=lVe324PqsI24");
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String inputLine;
        StringBuilder sb = new StringBuilder();
        while ((inputLine = br.readLine()) != null) {
            sb.append(inputLine);
        }
        br.close();
        return sb.toString();
    }
    @Override
    boolean extractorMatches(URL url) {
        return url ==~ VALID_WEB_RESOURCE_URL
    }

    @Override
    int getVersion() {
        return 2;
    }
    @Override
    String getExtractorName() {
        return getClass().getName()
    }
    static void main(args) {
        //def testUrl = new URL("http://seasonvar.ru/serial-6432-Vikingi.html");
        def testUrl = new URL("http://seasonvar.ru/serial-7004-SHkola_vyzhivaniya_v_mire_nasekomyh.html");
        SeasonVar extractor = new SeasonVar() ;
        println "PluginName               : " + extractor.getExtractorName();
        println "TestMatch                : " + extractor.extractorMatches(testUrl);
        WebResourceContainer container = extractor.extractItems(testUrl, -1);
        container.getItems().each {
            println "URL                  : " + extractor.extractUrl(it, PreferredQuality.HIGH)
        }

    }
}
