/* LanguageTool, a natural language style checker 
 * Copyright (C) 2018 Daniel Naber (http://www.danielnaber.de)
 * 
 * This library 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */
package org.languagetool.server;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.languagetool.Language;
import org.languagetool.Languages;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

public class UserDictTest {

  private static final String USERNAME1 = "test@test.de";
  private static final String API_KEY1 = "foo";
  private static final String USERNAME2 = "two@test.de";
  private static final String API_KEY2 = "foo-two";
  
  @Test
  public void testHTTPServer() throws Exception {
    HTTPServerConfig config = new HTTPServerConfig();
    config.setDatabaseDriver("org.hsqldb.jdbcDriver");
    config.setDatabaseUrl("jdbc:hsqldb:mem:testdb");
    config.setDatabaseUsername("");
    config.setDatabasePassword("");
    config.setSecretTokenKey("myfoo");
    config.setCacheSize(100);
    DatabaseAccess.init(config);
    try {
      DatabaseAccess.createAndFillTestTables();
      HTTPServer server = new HTTPServer(config);
      try {
        server.run();
        Language enUS = Languages.getLanguageForShortCode("en-US");
        runTests(enUS, "This is Mysurname.", "This is Mxsurname.", "Mysurname", "MORFOLOGIK_RULE_EN_US");
        runTests(enUS, "Mysurname is my name.", "Mxsurname is my name.", "Mysurname", "MORFOLOGIK_RULE_EN_US");
        Language deDE = Languages.getLanguageForShortCode("de-DE");
        runTests(deDE, "Das ist Meinname.", "Das ist Mxinname.", "Meinname", "GERMAN_SPELLER_RULE");
        runTests(deDE, "Meinname steht hier.", "Mxinname steht hier.", "Meinname", "GERMAN_SPELLER_RULE");
        runTests(deDE, "Hier steht Schöckl.", "Das ist Schückl.", "Schöckl", "GERMAN_SPELLER_RULE");
        try {
          addWord("multi word", USERNAME1, API_KEY1);
          fail("Should not be able to insert multi words");
        } catch (IOException ignore) {}
      } finally {
        server.stop();
      }
    } finally {
      DatabaseAccess.deleteTestTables();
    }
  }

  private void runTests(Language lang, String input, String inputWithTypo, String name, String errorRuleId) throws Exception {
    assertRuleMatch(1, input, lang, errorRuleId, USERNAME1, API_KEY1);
    assertRuleMatch(1, input, lang, errorRuleId, USERNAME2, API_KEY2);
    assertRuleMatch(1, input, lang, errorRuleId, null, null);  // anonymous user
    addWord(name, USERNAME1, API_KEY1);
    assertRuleMatch(0, input, lang, errorRuleId, USERNAME1, API_KEY1);
    assertRuleMatch(1, input, lang, errorRuleId, USERNAME2, API_KEY2);  // cache must not mix up users
    assertRuleMatch(1, input, lang, errorRuleId, null, null);  // anonymous user
    assertRuleMatch(0, input, lang, errorRuleId, USERNAME1, API_KEY1);
    String json = assertRuleMatch(1, inputWithTypo, lang, errorRuleId, USERNAME1, API_KEY1);
    assertTrue("Missing suggestion '" + name + "': " + json, json.contains("\"" + name + "\"") || json.contains("\"" + name + ".\""));
    deleteWord(name, USERNAME1, API_KEY1);
    assertRuleMatch(1, input, lang, errorRuleId, USERNAME1, API_KEY1);
    assertRuleMatch(1, input, lang, errorRuleId, USERNAME2, API_KEY2);
    assertRuleMatch(1, input, lang, errorRuleId, null, null);
  }

  private String assertRuleMatch(int expectedTypoCount, String input, Language lang, String errorRuleId, String username, String apiKey) throws IOException {
    String json = check(lang, input, username, apiKey);
    int realTypoCount = StringUtils.countMatches(json, errorRuleId);
    //System.out.println(json);
    assertThat("Expected " + expectedTypoCount + " rule matches (id " + errorRuleId + ") for '" + input + "', got " +
               realTypoCount, realTypoCount, is(expectedTypoCount));
    return json;
  }

  private String check(Language lang, String text, String username, String apiKey) throws IOException {
    String urlOptions = "?language=" + lang.getShortCodeWithCountryAndVariant();
    urlOptions += "&text=" + URLEncoder.encode(text, "UTF-8");
    if (username != null && apiKey != null) {
      urlOptions += "&username=" + URLEncoder.encode(username, "UTF-8");
      urlOptions += "&apikey=" + URLEncoder.encode(apiKey, "UTF-8");
    }
    URL url = new URL("http://localhost:" + HTTPTools.getDefaultPort() + "/v2/check" + urlOptions);
    return HTTPTools.checkAtUrl(url);
  }

  private String addWord(String word, String username, String apiKey) throws IOException {
    URL url = new URL("http://localhost:" + HTTPTools.getDefaultPort() + "/v2/words/add");
    return HTTPTools.checkAtUrlByPost(url, "word=" + word + "&username=" + username + "&apikey=" + apiKey);  // needs access to https://languagetoolplus.com/token
  }  
  
  private void deleteWord(String word, String username, String apiKey) throws IOException {
    URL url = new URL("http://localhost:" + HTTPTools.getDefaultPort() + "/v2/words/delete");
    HTTPTools.checkAtUrlByPost(url, "word=" + word + "&username=" + username + "&apikey=" + apiKey);  // needs access to https://languagetoolplus.com/token
  }
  
}

@@ -2621,32 +2621,284 @@
 SPELLER_RULE%22);%0A
+        String res = check(deDE, %22Hier steht Schockl%22, USERNAME1, API_KEY1);%0A        assertThat(StringUtils.countMatches(res, %22GERMAN_SPELLER_RULE%22), is (1));  // 'Sch%C3%B6ckl' accepted, but not 'Schockl' (NOTE: depends on encoding/collation of database) %0A
         try %7B%0A  

extend test