<?php

use Mockery as m;

use EasyRdf\Http;

class LexvoResolverTest extends TestCase
{
    const LEXVO_EMPTY_RDF_RESP = <<<EOT
{
  "head" : {
    "vars" : [
      "s",
      "o"
    ]
  },
  "results" : {
    "bindings" : [ ]
  }
}
EOT;
    const LEXVO_FRA_RDF_RESP = <<<EOT
{
  "head" : {
    "vars" : [
      "s",
      "o"
    ]
  },
  "results" : {
    "bindings" : [
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "French"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "French language"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "fr",
          "type" : "literal",
          "value" : "Français"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "fr",
          "type" : "literal",
          "value" : "français"
        }
      }
    ]
  }
}
EOT;

const LEXVO_FRA2_RDF_RESP = <<<EOT
{
    "head" : {
        "vars" : [
            "s",
            "o"
        ]
    },
    "results" : {
        "bindings" : [
            {
                "s" : {
                    "type" : "uri",
                    "value" : "http://lexvo.org/id/iso639-3/fra"
                },
                "o" : {
                    "xml:lang" : "en",
                    "type" : "literal",
                    "value" : "French"
                }
            },
            {
                "s" : {
                    "type" : "uri",
                    "value" : "http://lexvo.org/id/iso639-3/fra"
                },
                "o" : {
                    "xml:lang" : "en",
                    "type" : "literal",
                    "value" : "French language"
                }
            },
            {
                "s" : {
                    "type" : "uri",
                    "value" : "http://lexvo.org/id/iso639-3/fra"
                },
                "o" : {
                    "xml:lang" : "fr",
                    "type" : "literal",
                    "value" : "français"
                }
            },
            {
                "s" : {
                    "type" : "uri",
                    "value" : "http://lexvo.org/id/iso639-3/fra"
                },
                "o" : {
                    "xml:lang" : "fr",
                    "type" : "literal",
                    "value" : "Français"
                }
            }
        ]
    }
}
EOT;

    const LEXVO_FRA_AFR_RDF_RESP = <<<EOT
{
  "head" : {
    "vars" : [
      "s",
      "o"
    ]
  },
  "results" : {
    "bindings" : [
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "French"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "French language"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "fr",
          "type" : "literal",
          "value" : "Français"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/fra"
        },
        "o" : {
          "xml:lang" : "fr",
          "type" : "literal",
          "value" : "français"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/afr"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "Afrikaans"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/afr"
        },
        "o" : {
          "xml:lang" : "fr",
          "type" : "literal",
          "value" : "Afrikaans"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/afr"
        },
        "o" : {
          "xml:lang" : "fr",
          "type" : "literal",
          "value" : "afrikaans"
        }
      }
    ]
  }
}
EOT;
    const LEXVO_XAG_RDF_RESP = <<<EOT
{
  "head" : {
    "vars" : [
      "s",
      "o"
    ]
  },
  "results" : {
    "bindings" : [
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/xag"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "Aghwan"
        }
      },
      {
        "s" : {
          "type" : "uri",
          "value" : "http://lexvo.org/id/iso639-3/xag"
        },
        "o" : {
          "xml:lang" : "en",
          "type" : "literal",
          "value" : "Caucasian Albanian language"
        }
      }
    ]
  }
}
EOT;

const LEXVO_XAG2_RDF_RESP = <<<EOT
{
"head" : {
"vars" : [
  "s",
  "o"
]
},
"results" : {
"bindings" : [
    {
      "s" : {
        "type" : "uri",
        "value" : "http://lexvo.org/id/iso639-3/xag"
      },
      "o" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "Caucasian Albanian language"
      }
  },
  {
    "s" : {
      "type" : "uri",
      "value" : "http://lexvo.org/id/iso639-3/xag"
    },
    "o" : {
      "xml:lang" : "en",
      "type" : "literal",
      "value" : "Aghwan"
    }
  }
]
}
}
EOT;

    private function setUpSparqlClient($queryResult) {
        $response = m::mock('EasyRdf\Http\Response')
            ->shouldReceive('isSuccessful')->andReturn(true)
            ->shouldReceive('getBody')->andReturn($queryResult)
            ->shouldReceive('getStatus')->andReturn(200)
            ->shouldReceive('getHeader')->andReturn('application/sparql-results+json;charset=UTF-8')
            ->mock();
        $this->httpClient = m::mock('EasyRdf\Http\Client')
            ->shouldReceive('setConfig')
            ->shouldReceive('resetParameters')
            ->shouldReceive('setHeaders')//->with(m::on(function($headers) { print("HEADER => $headers\n"); return true;}),m::on(function($value) { print("VALUE => $value\n"); return true;}))
            ->shouldReceive('setMethod')
            ->shouldReceive('setUri')//->with(m::on(function($uri) { print($uri."\n"); return true;}))
            ->shouldReceive('request')->andReturn($response)
            ->mock();
        Http::setDefaultHttpClient($this->httpClient);
        $this->lexvoResolver = $this->app->make('CorpusParole\Services\LexvoResolverInterface');
    }

    public function setUp() {
        parent::setUp();
    }

    public function tearDown() {
        parent::tearDown();
        m::close();
    }

    /**
     * Just test the setup
     *
     * @return void
     */
    public function testSetUp() {
        $this->assertTrue(true);
    }

    /**
     * resolve french
     * @return void
     */
    public function testResolveSingleId() {

        $this->setUpSparqlClient(self::LEXVO_FRA_RDF_RESP);

        $resName = $this->lexvoResolver->getName('fra');

        $this->assertEquals('français', $resName, "Result must be français");
    }

    /**
     * resolve french
     * @return void
     */
    public function testResolveSingleIdFullURL() {

        $this->setUpSparqlClient(self::LEXVO_FRA_RDF_RESP);

        $resName = $this->lexvoResolver->getName('http://lexvo.org/id/iso639-3/fra');

        $this->assertEquals('français', $resName, "Result must be français");
    }

    /**
     * resolve foo
     * @return void
     */
    public function testResolveBadId() {

        $this->setUpSparqlClient(self::LEXVO_EMPTY_RDF_RESP);

        $resName = $this->lexvoResolver->getName('foo');

        $this->assertNull($resName, "Result must be null");
    }

    /**
     * resolve foo
     * @return void
     * @expectedException        CorpusParole\Services\LexvoResolverException
     * @expectedExceptionMessage the provided id "21dsasd;;" is not a Lexvo id
     * @expectedExceptionCode 0
     */
    public function testResolveBadFormat() {

        $this->setUpSparqlClient(self::LEXVO_EMPTY_RDF_RESP);

        $resName = $this->lexvoResolver->getName('21dsasd;;');
    }

    /**
     * resolve foo
     * @return void
     * @expectedException        CorpusParole\Services\LexvoResolverException
     * @expectedExceptionMessage the provided id "http://sdsasd.org/foo" is not a Lexvo id
     * @expectedExceptionCode 0
     */
    public function testResolveBadFormatFullId() {

        $this->setUpSparqlClient(self::LEXVO_EMPTY_RDF_RESP);

        $resName = $this->lexvoResolver->getName('http://sdsasd.org/foo');
    }


    /**
     * resolve french
     * @return void
     */
    public function testResolveMultipleId() {

        $this->setUpSparqlClient(self::LEXVO_FRA_AFR_RDF_RESP);

        $resnames = $this->lexvoResolver->getNames(['fra', 'afr']);

        $this->assertCount(2, $resnames, "Must have 2 results");
        $this->assertArrayHasKey('fra', $resnames);
        $this->assertArrayHasKey('afr', $resnames);

        $this->assertEquals('français', $resnames['fra'], "Result for fra must be français");
        $this->assertEquals('afrikaans', $resnames['afr'], "Result for afr must be afrikaans");
    }

    /**
     * resolve french
     * @return void
     */
    public function testResolveMultipleFullId() {

        $this->setUpSparqlClient(self::LEXVO_FRA_AFR_RDF_RESP);

        $resnames = $this->lexvoResolver->getNames(['http://lexvo.org/id/iso639-3/fra', 'http://lexvo.org/id/iso639-3/afr']);

        $this->assertCount(2, $resnames, "Must have 2 results");
        $this->assertArrayHasKey('http://lexvo.org/id/iso639-3/fra', $resnames);
        $this->assertArrayHasKey('http://lexvo.org/id/iso639-3/afr', $resnames);

        $this->assertEquals('français', $resnames['http://lexvo.org/id/iso639-3/fra'], "Result for fra must be français");
        $this->assertEquals('afrikaans', $resnames['http://lexvo.org/id/iso639-3/afr'], "Result for afr must be afrikaans");
    }

    /**
     * check query
     * @return void
     */
    public function testQuery() {

        $expectedUri = config('corpusparole.lexvo_rdf4j_query_url')."?query=PREFIX+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0ASELECT+%3Fs+%3Fo+WHERE+%7B%7B%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Ffra%3E+rdfs%3Alabel+%3Fo.+%3Fs+rdfs%3Alabel+%3Fo+FILTER%28%3Fs+%3D+%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Ffra%3E+%26%26+%28lang%28%3Fo%29+%3D+%22fr%22+%7C%7C+lang%28%3Fo%29+%3D+%22en%22%29%29%7D+UNION+%7B%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Fafr%3E+rdfs%3Alabel+%3Fo.+%3Fs+rdfs%3Alabel+%3Fo+FILTER%28%3Fs+%3D+%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Fafr%3E+%26%26+%28lang%28%3Fo%29+%3D+%22fr%22+%7C%7C+lang%28%3Fo%29+%3D+%22en%22%29%29%7D%7D";
        $response = m::mock('EasyRdf\Http\Response')
            ->shouldReceive('isSuccessful')->andReturn(true)
            ->shouldReceive('getBody')->andReturn(self::LEXVO_EMPTY_RDF_RESP) //result not important
            ->shouldReceive('getStatus')->andReturn(200)
            ->shouldReceive('getHeader')->andReturn('application/sparql-results+json;charset=UTF-8')
            ->mock();
        $this->httpClient = m::mock('EasyRdf\Http\Client')
            ->shouldReceive('setConfig')
            ->shouldReceive('resetParameters')
            ->shouldReceive('setHeaders')//->with(m::on(function($headers) { print("HEADER => $headers\n"); return true;}),m::on(function($value) { print("VALUE => $value\n"); return true;}))
            ->shouldReceive('setMethod')
            ->shouldReceive('setUri')
            ->with($expectedUri)//->with(m::on(function($uri) { print($uri."\n"); return true;}))
            ->shouldReceive('request')->andReturn($response)
            ->mock();
        Http::setDefaultHttpClient($this->httpClient);
        $this->lexvoResolver = $this->app->make('CorpusParole\Services\LexvoResolverInterface');

        $resName = $this->lexvoResolver->getNames(['fra','afr']);

    }

    /**
     * check query
     * @return void
     */
    public function testQueryFullId() {

        $expectedUri = config('corpusparole.lexvo_rdf4j_query_url')."?query=PREFIX+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0ASELECT+%3Fs+%3Fo+WHERE+%7B%7B%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Ffra%3E+rdfs%3Alabel+%3Fo.+%3Fs+rdfs%3Alabel+%3Fo+FILTER%28%3Fs+%3D+%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Ffra%3E+%26%26+%28lang%28%3Fo%29+%3D+%22fr%22+%7C%7C+lang%28%3Fo%29+%3D+%22en%22%29%29%7D+UNION+%7B%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Fafr%3E+rdfs%3Alabel+%3Fo.+%3Fs+rdfs%3Alabel+%3Fo+FILTER%28%3Fs+%3D+%3Chttp%3A%2F%2Flexvo.org%2Fid%2Fiso639-3%2Fafr%3E+%26%26+%28lang%28%3Fo%29+%3D+%22fr%22+%7C%7C+lang%28%3Fo%29+%3D+%22en%22%29%29%7D%7D";
        $response = m::mock('EasyRdf\Http\Response')
            ->shouldReceive('isSuccessful')->andReturn(true)
            ->shouldReceive('getBody')->andReturn(self::LEXVO_EMPTY_RDF_RESP) //result not important
            ->shouldReceive('getStatus')->andReturn(200)
            ->shouldReceive('getHeader')->andReturn('application/sparql-results+json;charset=UTF-8')
            ->mock();
        $this->httpClient = m::mock('EasyRdf\Http\Client')
            ->shouldReceive('setConfig')
            ->shouldReceive('resetParameters')
            ->shouldReceive('setHeaders')//->with(m::on(function($headers) { print("HEADER => $headers\n"); return true;}),m::on(function($value) { print("VALUE => $value\n"); return true;}))
            ->shouldReceive('setMethod')
            ->shouldReceive('setUri')
            ->with($expectedUri)//->with(m::on(function($uri) { print($uri."\n"); return true;}))
            ->shouldReceive('request')->andReturn($response)
            ->mock();
        Http::setDefaultHttpClient($this->httpClient);
        $this->lexvoResolver = $this->app->make('CorpusParole\Services\LexvoResolverInterface');

        $resName = $this->lexvoResolver->getNames(['http://lexvo.org/id/iso639-3/fra','http://lexvo.org/id/iso639-3/afr']);

    }

    /**
     * resolve french
     * @return void
     */
    public function testResolveSingleIdNofr() {

        $this->setUpSparqlClient(self::LEXVO_XAG_RDF_RESP);

        $resName = $this->lexvoResolver->getName('xag');

        $this->assertEquals('aghwan', $resName, "Result must be aghwan");
    }

    /**
     * resolve french
     * @return void
     */
    public function testResolveSingleIdOrderNotFr() {

        $this->setUpSparqlClient(self::LEXVO_XAG2_RDF_RESP);

        $resName = $this->lexvoResolver->getName('xag');

        $this->assertEquals('aghwan', $resName, "Result must be aghwan");
    }

    /**
     * resolve french
     * @return void
     */
    public function testResolveSingleIdOrder() {

        $this->setUpSparqlClient(self::LEXVO_FRA2_RDF_RESP);

        $resName = $this->lexvoResolver->getName('fra');

        $this->assertEquals('français', $resName, "Result must be français");
    }

}
