import groovy.json.JsonSlurper
import org.serviio.library.metadata.MediaFileType
import org.serviio.library.online.*

import javax.net.ssl.HttpsURLConnection
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager

/**
 * WebResource extractor plugin for Google+
 *
 * @author Michael Mishalov
 * @version 1.0
 */
class GooglePlus extends WebResourceUrlExtractor{
    protected final static VALID_WEB_RESOURCE_URL                     = '^(?:https?://)?(?:www\\.)?plus.google.com/.*'
    protected 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'
    protected final static USER_ID_REGEX                              = /(?s)photos\/(.*?)\/albums\//
    protected final static USER_ALBUMS_REGEX                          = /(?s)_user.albums =(.*?);/
    protected final static NAME_ATR_REGEX                             = /(?s)name="(.*?)"/
    protected final static VALUE_ATR_REGEX                            = /(?s)value="(.*?)"/
    protected final static AUTH_FORM_REGEX                            = /(?s)<form novalidate(.*?)<\/form>/
    protected final static FEED_PRELOAD_REGEX                         = /(?s)feedPreload: (.*?),\{NEW_HOMEPAGE/
    protected final static ALBUM_ID_SLIT                              = "albums/"
    protected final static USER_GALLERY_URL                           = "https://picasaweb.google.com/%s?noredirect=1"
    protected static final int PLUGIN_VERSION                         = 1
    protected static final JSON_CONVERT_PATTERN                       = "JSON.stringify(%s);"
    public static final String AUTH_URL                               = "https://accounts.google.com/ServiceLoginAuth"
    private List<String> cookies;
    private HttpsURLConnection connection;
    @Override
    protected WebResourceContainer extractItems(URL url, int i) {
        // make sure cookies is turn on
        CookieHandler.setDefault(new CookieManager());
        String[] split = url.toString().split(" ")
        String userId =  ((split[0]=~USER_ID_REGEX)[0]-null)[-1].toString().trim()
        String albumId = split[0].split(ALBUM_ID_SLIT)[1];
        String username = null
        String password = null
        if(split.size()==2){
           split=split[1].split(",")
           username = split[0].split("=")[1]
           password = split[1].split("=")[1]
        }
        if(username!=null && password ){
            authenticate(username,password)
        }
        String pageSource = getPageContent(String.format(USER_GALLERY_URL,userId))
        String json =  ((pageSource=~USER_ALBUMS_REGEX)[0]-null)[-1].toString().trim()
        String jsSource = "json ="+ String.format(JSON_CONVERT_PATTERN,json);
        ScriptEngineManager manager = new ScriptEngineManager()
        ScriptEngine engine = manager.getEngineByName("JavaScript")
        engine.eval(jsSource);
        json = engine.get("json");
        def allAlbums = new JsonSlurper().parseText(json)
        String webResourceTitle="Unknown title"
        String thumbnailUrl="";
        List<WebResourceItem> items = []
        def album = allAlbums.find{albumData -> albumData.id==albumId }
        if(album!=null){
            webResourceTitle=album.title
            thumbnailUrl=album.src
            items.addAll(fetchItems(album))
        }
        return new WebResourceContainer(title: webResourceTitle ,thumbnailUrl:thumbnailUrl, items: items)
    }
    /**
     * Authenticate to G++ using username and password
     * */
    private void authenticate(String username, String password) throws Exception {
        String pageContent = getPageContent(AUTH_URL)
        String postParams = buildPostParams(pageContent,username, password)
        connection = (HttpsURLConnection) new URL(AUTH_URL).openConnection();
        connection.setUseCaches(false);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Host", "accounts.google.com");
        connection.setRequestProperty("User-Agent", USER_AGENT);
        connection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        connection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        if (cookies != null) {
            this.cookies.each {
                connection.addRequestProperty("Cookie", it.split(";", 1)[0]);
            }
        }
        connection.setRequestProperty("Connection", "keep-alive");
        connection.setRequestProperty("Referer", AUTH_URL);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        connection.setRequestProperty("Content-Length", Integer.toString(postParams.length()));
        connection.setDoOutput(true);
        connection.setDoInput(true);
        // Send post request
        DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
        wr.writeBytes(postParams);
        wr.flush();
        wr.close();
        // Read page content to get authentication
        String ignored = connection.getInputStream().text

    }
    /**
     * Get page content and keep cookies
     * */
    private String getPageContent(String url) throws Exception {
        connection = (HttpsURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("GET");
        connection.setUseCaches(false);
        connection.setRequestProperty("User-Agent", USER_AGENT);
        connection.setRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        connection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        if (cookies != null) {
            this.cookies.each {
                connection.addRequestProperty("Cookie", it.split(";", 1)[0]);
            }
        }
        int responseCode = connection.getResponseCode();
        String response = (responseCode==200)? connection.getInputStream().text:""
        cookies = connection.getHeaderFields().get("Set-Cookie")
        response
    }

    private String buildPostParams(String http, String username, String password) {
        String formHtml =  ((http=~AUTH_FORM_REGEX)[0]-null)[-1].toString().trim()
        formHtml = formHtml.replaceAll("\\r\\n|\\r|\\n", " ").replaceAll("'","\"")
        def paramList = []
        for (String inputElement:formHtml.split("input") )  {
            if(inputElement.contains("name") && inputElement.contains("value")){
                String name =  ((inputElement=~NAME_ATR_REGEX)[0]-null)[-1].toString().trim()
                String value = ((inputElement=~VALUE_ATR_REGEX)[0]-null)[-1].toString().trim()
                if (name.equals("Email"))
                    value = username;
                paramList << (name + "=" + URLEncoder.encode(value, "UTF-8"));
            }
        }
        paramList << ("Passwd=" + URLEncoder.encode(password, "UTF-8"));
        return paramList.join("&")
    }
    @Override
    protected ContentURLContainer extractUrl(WebResourceItem webResourceItem, PreferredQuality preferredQuality) {
        return new ContentURLContainer(fileType: MediaFileType.IMAGE,thumbnailUrl:webResourceItem.additionalInfo.thumbnailURL, contentUrl: webResourceItem.additionalInfo.sourceURL)
    }

    private List<WebResourceItem> fetchItems(album){
        List<WebResourceItem> items = [];
        String pageSource = getPageContent(album.url).replaceAll("\\r\\n|\\r|\\n", "")
        String json =  ((pageSource=~FEED_PRELOAD_REGEX)[0]-null)[-1].toString().trim()
        def feedPreload = new JsonSlurper().parseText(json)
        feedPreload.feed.entry.each{
            try{
                String width = it.media.thumbnail[-1].width
                String thumbnailURL = it.media.thumbnail[-1].url
                String clearURL = thumbnailURL.substring(0,thumbnailURL.indexOf("s"+width+"/"+it.title))
                String sourceURL = clearURL+"s"+it.width+"/"+it.title
                items << new WebResourceItem(title: it.title, additionalInfo:['sourceURL':sourceURL,'thumbnailURL':thumbnailURL])
            }catch (IndexOutOfBoundsException ignored){}
        }
        return items;
    }

    @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("https://plus.google.com/u/0/photos/107982474099703846460/albums/5924047856490871153")
        def TestUrl = new URL("https://plus.google.com/u/0/photos/106661386135469061222/albums/5641152189309370065")
        GooglePlus extractor = new GooglePlus()
        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;
        }

    }

}
