<?php
include_once __DIR__.'/SccRpcObject.php';

class SccAnalytics extends SccRpcObject {
    /** ディメンションオペレータ定数 */
    const DIMENTION_OPERATOR_EXACT = "==";
    const DIMENTION_OPERATOR_PARTIAL = "=@";
    const DIMENTION_OPERATOR_REGEXP = "=~";
    const DIMENTION_OPERATOR_EXACT_DENY = "!=";
    const DIMENTION_OPERATOR_PARTIAL_DENY = "!@";
    const DIMENTION_OPERATOR_REGEXP_DENY = "!~";
    const DIMENTION_OPERATOR_EXACT_SINGLE = "=";

    const DIMENTION_OPERATOR_OPTION_EXACT = "EXACT";
    const DIMENTION_OPERATOR_OPTION_PARTIAL = "PARTIAL";
    const DIMENTION_OPERATOR_OPTION_REGEXP = "REGEXP";
    const DIMENTION_OPERATOR_OPTION_EXACT_DENY = "EXACT";
    const DIMENTION_OPERATOR_OPTION_PARTIAL_DENY = "PARTIAL";
    const DIMENTION_OPERATOR_OPTION_REGEXP_DENY = "REGEXP";
    const DIMENTION_OPERATOR_OPTION_EXACT_SINGLE = "EXACT";


    protected $remote_method_list = array();

    public function __construct() {
        //公開するメソッドを登録する
        $this->remote_method_list = array(
            'getGoogleAnalytics'=>array('proc_lock'=>false),
            'getGoogleAnalyticsV4'=>array('proc_lock'=>false)
        );
    }

    //指定されたメソッドが実装されているかどうかチェックする
    public function existMethod($methodName) {
        return (array_key_exists($methodName, $this->remote_method_list) && method_exists($this, $methodName));
    }
    /**
     * (non-PHPdoc)
     * @see SccRpcObject::canProccessLock()
     */
    public function canProccessLock($methodName) {
        return $this->remote_method_list[$methodName]['proc_lock'];
    }
    /**
     * (non-PHPdoc)
     * @see SccRpcObject::getClassName()
     */
    protected function getClassName() {
        return get_class($this);
    }
    /**
     * (non-PHPdoc)
     * @see SccRpcObject::getLockInterval()
     */
    protected function getLockInterval($methodName) {
        return 1;
    }
    /**
     * (non-PHPdoc)
     * @see SccRpcObject::getLockRetryTimes()
     */
    protected function getLockRetryTimes($methodName) {
        return 5;
    }

    /**
     * Google AnalyticsのAPIを介してGAのデータを取得する
     */
    public function getGoogleAnalytics($params) {
        try{
            $util = new ApiUtils();

            //ライブラリを読み込む
            require_once __DIR__."/lib/google-api-php-client-master/src/Google/autoload.php";

            //パラメータのチェック
            if (empty($params['client_email']) || empty($params['view_id']) || empty($params['key_file']) || empty($params['metrics'])) {
                throw new Exception("Required parameter isn't set.");
            }

            //メールアドレス
            $client_email = $params['client_email'];
            //ビューID
            $view_id = $params['view_id'];

            //秘密キーファイルの読み込み
            //$private_key = @file_get_contents("/var/www/keys/".$params['key_file']);
            $private_key = @file_get_contents(MAIN_PATH.'/parcocity_cms/app_front_module/gapi/application/models/api/private_key/'.$params['key_file']);

            //取得する期間（期間指定なしできる？）
            $from = $params['start_date'];        //対象開始日
            $to = $params['end_date'];        //対象終了日

            $metrics = $params['metrics'];    //メトリクス

            //オプション
            $option = array();
            //ディメンションの設定[,で区切る]
            if (!empty($params['dimensions'])) {
                $option += array("dimensions" => $params['dimensions']);
            }
            //ソート
            if (!empty($params['sort'])) {
                $option += array("sort" => $params['sort']);
            }
            //取得件数(最大1,000件)
            if (!empty($params['max-results']) && is_numeric($params['max-results'])) {
                $option += array("max-results" => $params['max-results']);
            }
            //フィルター
            if (!empty($params['filters'])) {
                $option += array("filters" => $params['filters']);
            }
            //オフセット
            if (!empty($params['start-index'])) {
                $option += array("start-index" => $params['start-index']);
            }

            //トークンのセット
            if(isset($_SESSION["service_token"])){
                $client->setAccessToken($_SESSION["service_token"]);
            }

            //スコープのセット(とりあえず固定)
            $scopes = array("https://www.googleapis.com/auth/analytics.readonly");

            //クレデンシャルの作成
            $credentials = new Google_Auth_AssertionCredentials($client_email,$scopes,$private_key);

            //Googleクライアントのインスタンスを作成
            $client = new Google_Client();
            $client->setAssertionCredentials($credentials);

            //トークンのリフレッシュ
            if($client->getAuth()->isAccessTokenExpired()){
            $client->getAuth()->refreshTokenWithAssertion($credentials);
            }
            $_SESSION["service_token"] = $client->getAccessToken();

            //Analyticsのインスタンスを作成
            $analytics = new Google_Service_Analytics($client);

            //データの取得
            $obj = $analytics->data_ga->get("ga:{$view_id}",$from,$to,$metrics,$option);

            //JSONデータに変換して出力
            //$ret = json_encode($obj);

            return $obj;
        }
        catch(Exception $e) {
            throw new Exception($e->getMessage());
        }

    }

    /**
     * Google AnalyticsのAPI(V4)を介してGAのデータを取得する
     */
    public function getGoogleAnalyticsV4($params)
    {
        try {
            $util = new ApiUtils();

            //ライブラリを読み込む
            require_once __DIR__."/lib/v4/vendor/autoload.php";

            //パラメータのチェック
            if (empty($params['client_email']) || empty($params['view_id']) || empty($params['key_file']) || empty($params['metrics'])) {
                throw new Exception("Required parameter isn't set.");
            }

            //メールアドレス
            $client_email = $params['client_email'];
            //ビューID
            $view_id = $params['view_id'];

            //秘密キーファイルの読み込み(jsonのみ対応)
            //$private_key = @file_get_contents(MAIN_PATH.'/parcocity_cms/app_front_module/gapi/application/models/api/private_key/'.$params['key_file']);
            $private_key = __DIR__."/../private_key/".$params['key_file'];

            //取得する期間（期間指定なしできる？）
            $from = $params['start_date'];        //対象開始日
            $to = $params['end_date'];        //対象終了日

            $metrics = $params['metrics'];    //メトリクス

            //初期設定
            $client = new Google_Client();
//             $client->setApplicationName("Hello Analytics Reporting");
            $client->setAuthConfig($private_key);
//             $client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
            $client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
            $analytics = new Google_Service_AnalyticsReporting($client);

            //条件を指定してデータを取得
            $request = new Google_Service_AnalyticsReporting_ReportRequest();
            $request->setViewId($view_id);

            //取得する期間（期間指定なしできる？）
            $dateRange = new Google_Service_AnalyticsReporting_DateRange();
            $dateRange->setStartDate($from);
            $dateRange->setEndDate($to);
            $request->setDateRanges($dateRange);

            //メトリクス
            $sessions = new Google_Service_AnalyticsReporting_Metric();
            $sessions->setExpression($metrics);
            //$sessions->setAlias("sessions"); //とりあえずコメント
            $request->setMetrics(array($sessions));

            //ディメンション
            if (!empty($params['dimensions'])) {
                $dimension = new Google_Service_AnalyticsReporting_Dimension();
                $dimension->setName($params['dimensions']);
                $request->setDimensions($dimension);
            }

            //ソート
            if (!empty($params['sort'])) {
                $sortList = array_map("trim", explode(",", $params["sort"]));

                $idx = 0;
                $orderBy = array();
                foreach ($sortList as $sortData) {
                    $orderBy[$idx] = new Google_Service_AnalyticsReporting_OrderBy();
                    if (substr($sortData, 0, 1) === '-') {
                        $orderBy[$idx]->setSortOrder('DESCENDING');
                        $sortData = substr($sortData, 1);
                    }
                    $orderBy[$idx]->setFieldName($sortData);
                }
                $request->setOrderBys($orderBy);
            }

            //フィルター
            if (!empty($params['filters'])) {
                //"filters"=>"ga:pagePath=@/shopblog/detail/index.html?scd=,ga:pagePath=@/shopblog/list/index.html?scd=,ga:pagePath=@/shopblog/detail/index.html?p=,ga:pagePath=@/shopblog/list/index.html?p=",);
                //カンマ区切り(OR指定)で複数指定可のため区切る
                $filList = array_map("trim", explode(",", $params["filters"]));

                //指定されたフィルターの演算子から、演算子情報及びv4オプション文字列を取得する
                $getDimensionOperator = function ($parmStr) {
                    if (strpos($parmStr, self::DIMENTION_OPERATOR_EXACT) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_EXACT, "option"=>self::DIMENTION_OPERATOR_OPTION_EXACT);
                    } elseif (strpos($parmStr, self::DIMENTION_OPERATOR_EXACT_DENY) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_EXACT_DENY, "option"=>self::DIMENTION_OPERATOR_OPTION_EXACT_DENY);
                    } elseif (strpos($parmStr, self::DIMENTION_OPERATOR_PARTIAL) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_PARTIAL, "option"=>self::DIMENTION_OPERATOR_OPTION_PARTIAL);
                    } elseif (strpos($parmStr, self::DIMENTION_OPERATOR_PARTIAL_DENY) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_PARTIAL_DENY, "option"=>self::DIMENTION_OPERATOR_OPTION_PARTIAL_DENY);
                    } elseif (strpos($parmStr, self::DIMENTION_OPERATOR_REGEXP) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_REGEXP, "option"=>self::DIMENTION_OPERATOR_OPTION_REGEXP);
                    } elseif (strpos($parmStr, self::DIMENTION_OPERATOR_REGEXP_DENY) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_REGEXP_DENY, "option"=>self::DIMENTION_OPERATOR_OPTION_REGEXP_DENY);
                    } elseif (strpos($parmStr, self::DIMENTION_OPERATOR_EXACT_SINGLE) !== false) {
                        return array("operator"=>self::DIMENTION_OPERATOR_EXACT_SINGLE, "option"=>self::DIMENTION_OPERATOR_OPTION_EXACT_SINGLE);
                    }
                };

                $idx = 0;
                $filter = array();
                foreach ($filList as $filData) {
                    $filter[$idx] = new Google_Service_AnalyticsReporting_DimensionFilter();
                    $operatorObj = $getDimensionOperator($filData);
                    $dimNm = substr($filData, 0, strpos($filData, $operatorObj["operator"]));
                    $filter[$idx]->setDimensionName($dimNm);
                    if ($operatorObj["operator"] === self::DIMENTION_OPERATOR_EXACT_DENY ||
                        $operatorObj["operator"] === self::DIMENTION_OPERATOR_PARTIAL_DENY ||
                        $operatorObj["operator"] === self::DIMENTION_OPERATOR_REGEXP_DENY) {
                        //否定形
                        $filter[$idx]->setNot(true);
                    }
                    $filter[$idx]->setOperator($operatorObj["option"]);
//                     $filter[$idx]->setOperator("PARTIAL");
                    $filter[$idx]->setExpressions( array(substr($filData, strpos($filData, $operatorObj["operator"])+strlen($operatorObj["operator"]))) );
                    $idx++;
                }

                $filters = new Google_Service_AnalyticsReporting_DimensionFilterClause();
                $filters->setFilters($filter);
                $request->setDimensionFilterClauses($filters);
            }


            //取得件数(最大1,000件)
            if (!empty($params['max-results']) && is_numeric($params['max-results'])) {
                $request->setPageSize($params['max-results']);
            }

            //オフセット
            if (!empty($params['start-index'])) {
                $val = $params['start-index'] - 1;
                $request->setPageToken((string) $val);
            }

            $body = new Google_Service_AnalyticsReporting_GetReportsRequest();
            //V4はバッチリクエストに対応しているが現状は利用しない（v3との兼ね合い）
            $body->setReportRequests( array( $request) );
            $obj = $analytics->reports->batchGet( $body );
            //JSONデータに変換して出力
            //$ret = json_encode($obj);

            //リターンフォーマット（デフォルトはV3フォーマットとする）
            if (empty($params['format']) || strtolower($params['format']) !== "v4") {
                //v4の結果リストからv3の結果リストの形式に変換する
                $report = $obj['reports'][0];//バッチリクエスト未使用のため要素は「0」固定
                $rowCnt = count($report['data']['rows']);

                $v3List = array();
                $v3List["containsSampledData"] = false;
                $v3List["id"] = "";
                $v3List["itemsPerPage"] = $rowCnt;
                $v3List["kind"] = "";
                $v3List["nextLink"] = "";
                $v3List["previousLink"] = "";
                $v3List["sampleSize"] = "";
                $v3List["sampleSpace"] = "";
                $v3List["selfLink"] = "";
                $v3List["totalResults"] = $report["data"]["rowCount"];

                $metricHeaderEntries = $report["columnHeader"]["metricHeader"]["metricHeaderEntries"];
                for ($i = 0; $i < count($metricHeaderEntries); $i++) {
                    $v3List["totalsForAllResults"][] = array(
                        $metricHeaderEntries[$i]["name"]=>$report["totals"][$i]["values"][0]
                    );
                }

                //rowデータの取り出し
                $v3List["rows"] = array();
                foreach ($report['data']['rows'] as $row) {
                    $dimensions = $row['dimensions'];
                    $metrics = $row['metrics'];

                    //指標値のカウント
                    $cnt = 0;
                    foreach ($metrics as $metData) {
                        foreach ($metData as $val) {
                            $cnt = $val;
                        }
                    }

                    //パス&指標値のセット
                    $v3List["rows"][] = array($dimensions[0], $cnt);
                }
                $obj = $v3List;
            }
            return $obj;
        } catch(Exception $e) {
            throw new Exception($e->getMessage());
        }
    }
}
?>