package org.knowm.xchange.bitmex;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.knowm.xchange.bitmex.dto.account.BitmexTicker;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.exceptions.ExchangeException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

/**
 * @author timmolter
 */
public class BitmexUtils {

  protected static Map<String, CurrencyPair> assetPairMap = new HashMap<String, CurrencyPair>();
  protected static BiMap<String, BitmexContract> bitmexContracts = HashBiMap.create();
  protected static BiMap<Currency, String> bitmexCurrencies = HashBiMap.create();
  protected static final HashBiMap<String, Currency> assetsMap = HashBiMap.create();

  /**
   * Private Constructor
   */
  private BitmexUtils() {

  }

  public static void setBitmexAssetPairs(List<BitmexTicker> tickers) {

    if (assetPairMap.isEmpty() || assetsMap.isEmpty()) {
      for (BitmexTicker ticker : tickers) {
        String quote = ticker.getQuoteCurrency();
        String base = ticker.getRootSymbol();
        Currency baseCurrencyCode = Currency.getInstance(base);
        Currency quoteCurrencyCode = Currency.getInstance(quote);

        CurrencyPair pair = new CurrencyPair(base, quote);
        if (!assetPairMap.containsKey(ticker.getSymbol()) && !assetPairMap.containsValue(pair))
          assetPairMap.put(ticker.getSymbol(), pair);
        if (!assetsMap.containsKey(quote) && !assetsMap.containsValue(quoteCurrencyCode))
          assetsMap.put(quote, quoteCurrencyCode);
        if (!assetsMap.containsKey(base) && !assetsMap.containsValue(baseCurrencyCode))
          assetsMap.put(base, baseCurrencyCode);

      }

    }

  }

  public static String createBitmexContract(BitmexContract contract) {

    return bitmexContracts.inverse().get(contract);
  }

  public class CustomBitmexContractSerializer extends JsonSerializer<BitmexContract> {

    @Override
    public void serialize(BitmexContract contract, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

      jsonGenerator.writeString(contract.toString());

    }
  }

  public static CurrencyPair translateBitmexCurrencyPair(String currencyPairIn) {

    CurrencyPair pair = assetPairMap.get(currencyPairIn);
    if (pair == null) {
      // bitmex can give short pairs back from open orders ?
      if (currencyPairIn.length() == 6) {
        Currency base = new Currency(currencyPairIn.substring(0, 3));
        if (base.getCommonlyUsedCurrency() != null) {
          base = base.getCommonlyUsedCurrency();
        }
        Currency counter = new Currency(currencyPairIn.substring(3, 6));
        if (counter.getCommonlyUsedCurrency() != null) {
          counter = counter.getCommonlyUsedCurrency();
        }
        pair = new CurrencyPair(base, counter);
      }
      else if (currencyPairIn.length() == 7) {
        Currency base = new Currency(currencyPairIn.substring(0, 4));
        if (base.getCommonlyUsedCurrency() != null) {
          base = base.getCommonlyUsedCurrency();
        }
        Currency counter = new Currency(currencyPairIn.substring(4, 7));
        if (counter.getCommonlyUsedCurrency() != null) {
          counter = counter.getCommonlyUsedCurrency();
        }
        pair = new CurrencyPair(base, counter);
      }
    }
    return pair;
  }

  public static String getBitmexCurrencyCode(Currency currency) {

    if (currency.getIso4217Currency() != null) {
      currency = currency.getIso4217Currency();
    }
    String bitmexCode = assetsMap.inverse().get(currency);
    if (bitmexCode == null) {
      throw new ExchangeException("Bitmex does not support the currency code " + currency);
    }
    return bitmexCode;
  }

  public static String translateCurrency(Currency currencyIn) {

    String currencyOut = bitmexCurrencies.get(currencyIn);

    if (currencyOut == null) {
      throw new ExchangeException("Bitmex does not support the currency code " + currencyIn);
    }
    return currencyOut;
  }

  public static Currency translateBitmexCurrency(String currencyIn) {

    Currency currencyOut = bitmexCurrencies.inverse().get(currencyIn);

    if (currencyOut == null) {
      throw new ExchangeException("Bitmex does not support the currency code " + currencyIn);
    }
    return currencyOut;
  }

  public static String translateBitmexContract(BitmexContract contractIn) {

    String contractOut = bitmexContracts.inverse().get(contractIn);

    if (contractOut == null) {
      throw new ExchangeException("Bitmex does not support the contact " + contractIn);
    }
    return contractOut;
  }

  public static Currency translateBitmexCurrencyCode(String currencyIn) {

    Currency currencyOut = assetsMap.get(currencyIn);
    if (currencyOut == null) {
      throw new ExchangeException("Bitmex does not support the currency code " + currencyIn);
    }
    return currencyOut.getCommonlyUsedCurrency();
  }
}

@@ -1134,67 +1134,8 @@
  %7B%0A%0A
-    if (assetPairMap.isEmpty() %7C%7C assetsMap.isEmpty()) %7B%0A  
     
@@ -1168,26 +1168,24 @@
  tickers) %7B%0A
-  
       String
@@ -1216,26 +1216,24 @@
 Currency();%0A
-  
       String
@@ -1262,34 +1262,32 @@
 Symbol();%0A      
-  
 Currency baseCur
@@ -1322,26 +1322,24 @@
 ance(base);%0A
-  
       Curren
@@ -1393,26 +1393,24 @@
 te);%0A%0A      
- 
- 
 CurrencyPair
@@ -1444,26 +1444,24 @@
 se, quote);%0A
-  
       if (!a
@@ -1546,26 +1546,24 @@
 r))%0A        
-  
 assetPairMap
@@ -1592,34 +1592,32 @@
 ), pair);%0A      
- 
- 
 if (!assetsMap.c
@@ -1682,34 +1682,32 @@
 yCode))%0A        
-  
 assetsMap.put(qu
@@ -1727,26 +1727,24 @@
 rencyCode);%0A
-  
       if (!a
@@ -1821,26 +1821,24 @@
 e))%0A        
-  
 assetsMap.pu
@@ -1869,17 +1869,8 @@
 );%0A%0A
-      %7D%0A%0A
     

allow updating of asset pairs, e.g. when connecting to testnet, which may have different symbols listed than live BitMEX