/*
 *
 * Copyright (c) 2017 UniqueStudio
 *
 * This file is part of ParsingPlayer.
 *
 * ParsingPlayer is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with ParsingPlayer; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

package com.hustunique.parsingplayer.parser.extractor;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.hustunique.parsingplayer.parser.ExtractException;
import com.hustunique.parsingplayer.parser.entity.Seg;
import com.hustunique.parsingplayer.parser.entity.Stream;
import com.hustunique.parsingplayer.parser.entity.VideoInfoImpl;
import com.hustunique.parsingplayer.util.LogUtil;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by CoXier on 17-1-17.
 */

public class YoukuExtractor extends Extractor {
    public static final String VALID_URL = "(?:http://(?:v|player)\\.youku\\.com/(?:v_show/id_|player\\.php/sid/)|youku:)([A-Za-z0-9]+)(?:\\.html|/v\\.swf|)";
    private static final String ID_REGEX = "((?<=id_)|(?<=sid/))[A-Za-z0-9]+";
    private static final String TAG = "YoukuExtractor";
    private static final char[] letterTable = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    public static final String TEST_URL = "http://v.youku.com/v_show/id_XMjUwODc1MTY5Mg==.html";


    private String mId;


    @Override
    @Nullable
    VideoInfoImpl createInfo(@NonNull Response response) throws IOException {
        JsonObject data = getData(response.body().string());
        if (data == null) return null;
        checkError(data);
        String title = getTitle(data);
        Map<Integer, Stream> streamMap = getSegMap(data);
        LogUtil.d(TAG, "hd length:" + streamMap.keySet().size());
        return new VideoInfoImpl(mUrl, streamMap, title, mId);
    }

    private Map<Integer, Stream> getSegMap(JsonObject data) throws UnsupportedEncodingException {
        HashMap<Integer, Stream> streamMap = new HashMap<>();
        JsonArray streams = data.getAsJsonArray("stream");
        for (JsonElement streamJson : streams) {
            if (streamJson.getAsJsonObject().get("channel_type") != null && streamJson.getAsJsonObject().get("channel_type").getAsString().equals("tail"))
                continue;
            List<Seg> segList = new ArrayList<>();

            JsonArray segJsons = streamJson.getAsJsonObject().getAsJsonArray("segs");
            for (JsonElement segJson : segJsons) {
                String url = segJson.getAsJsonObject().get("cdn_url").getAsString();
                double duration = segJson.getAsJsonObject().get("total_milliseconds_audio").getAsInt() / 1000;
                Seg seg = new Seg(url, duration);
                segList.add(seg);
            }

            int size = streamJson.getAsJsonObject().get("size").getAsInt();
            int height = streamJson.getAsJsonObject().get("height").getAsInt();
            int width = streamJson.getAsJsonObject().get("width").getAsInt();
            Stream stream = new Stream(segList, size, height, width);
            stream.setSize(size);
            streamMap.put(calQualityByHeight(height), stream);
        }
        return streamMap;
    }

    // Check error if response return error data
    private void checkError(JsonObject data) {
        if (data.has("error")) {
            LogUtil.e(TAG, "extract error: " + data.toString());
            JsonObject jsonObject = data.getAsJsonObject("error");
            String errorMsg = jsonObject.get("note").getAsString();
            // TODO: 1/25/17 Try to avoid hard-coding
            if (errorMsg.contains("该视频已经加密")) {
                throw new ExtractException("Youku said: Sorry, this video is private");
            } else if (errorMsg.contains("抱歉,该视频仅限中国大陆地区播放,请您观看其他视频!")) {
                throw new ExtractException("Youku said: Sorry, this video is available in China only");
            } else {
                throw new ExtractException("Youku server reported error " + jsonObject.get("error").getAsString());
            }
        }

    }

    // this may not be testable because it generates string randomly.
    private String getYsuid() {
        StringBuilder sb = new StringBuilder();
        int time = (int) (new Date().getTime() / 1000);
        sb.append(time);
        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            int offset = random.nextInt(letterTable.length);
            char c = letterTable[offset];
            sb.append(c);
        }
        return sb.toString();
    }

    @NonNull
    @Override
    Request buildRequest(@NonNull String baseUrl) {
        if (baseUrl == null) throw new IllegalArgumentException();
        String ysuid = getYsuid();
        Log.d(TAG, "set ysuid: " + ysuid);
        return new Request.Builder().url(baseUrl)
                .addHeader("Cookie", "xreferrer=http://www.youku.com;__ysuid=" + ysuid)
                .addHeader("Referer", baseUrl)
                .build();
    }

    @Override
    String constructBasicUrl(@NonNull String url) {
        mId = searchValue(url, ID_REGEX);
        if (mId == null)
            throw new IllegalArgumentException("Can't find id of this video.Please check");
        String clientIp = "192.168.1.1";
        String ccode = "0501";
        String urlh, cna = null;
        try {
            urlh = downloadData("https://log.mmstat.com/eg.js");
            cna = searchValue(urlh, "(?<=goldlog.Etag=\")[^\"]+");
        } catch (IOException e) {
            e.printStackTrace();
        }
        long time = System.currentTimeMillis() / 1000;
        String basicUrl = "https://ups.youku.com/ups/get.json?" +
                "vid=" + mId
                + "&ccode=" + ccode
                + "&client_ip=" + clientIp
                + "&utid=" + cna
                + "&client_ts=" + time;
        Log.i(TAG, "basic url" + basicUrl);
        return basicUrl;
    }

    private JsonObject getData(String response) {
        JsonParser jsonParser = new JsonParser();
        return jsonParser.parse(response).getAsJsonObject().getAsJsonObject("data");
    }

    private String getTitle(JsonObject data) {
        return data.getAsJsonObject("video").get("title").getAsString();
    }

}





@@ -5994,17 +5994,17 @@
 e = %22050
-1
+7
 %22;%0A     

Update ccode