@Component
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
	private String name;
	private String protocol;
	private String url;
	private List<String> admins;

	private final Db db = new Db();
	private final Rest rest = new Rest();
	private final Dropbox dropbox = new Dropbox();
	private final Email email = new Email();
	private final Report report = new Report();

	@Data
	public static class Db {
		private String ip;
		private String driver;
		private String name;
		private String user;
		private String password;
	}

	@Data
	public static class Rest {
		private final Client client = new Client();

		@Data
		public static class Client {
			private int maxTotalConnections;
			private int maxConnectionsPerRoute;
			private int readTimeout;
		}
	}

	@Data
	public static class Dropbox {
		private String clientId;
		private String accessToken;
	}

	@Data
	public static class Email {
		private final Smtp smtp = new Smtp();
		private final From from = new From();

		@Data
		public static class Smtp {
			private String host;
			private String port;
		}

		@Data
		public static class From {
			private String username;
			private String password;
			private String from;
		}
	}

	@Data
	public static class Report {
		private String ireport;
	}
} public enum Currency {
	AUD("Australia Dollar", "$", "AUD"),
	CAD("Canada Dollar", "$", "CAD"),
	// CHF("Switzerland Franc", "CHF", "CHF"),
	EUR("Euro", "€", "EUR"),
	GBP("United Kingdom Pound", "£", "GBP"),
	JPY("Japanese Yen", "¥", "JPY"),
	// HKD("Hong Kong Dollar", "$", "HKD"),
	// SGD("Singapore Dollar", "$", "SGD"),
	USD("United States Dollar", "$", "USD");
	// ZAR("South Africa Rand", "R", "ZAR");

	/**
	 * Constructor
	 *
	 * @param n  the name
	 * @param sy the symbol
	 * @param c  the code
	 */
	Currency(final String n, final String sy, final String c) {
		this.name = n;
		this.symbol = sy;
		this.code = c;
	}

	/**
	 * Get the name
	 *
	 * @return the name
	 */
	public final String getName() {
		return name;
	}

	/**
	 * Get Symbol
	 *
	 * @return the symbol
	 */
	public final String getSymbol() {
		return symbol;
	}

	/**
	 * Get the code
	 *
	 * @return the code
	 */
	public final String getCode() {
		return code;
	}

	/**
	 * Get a list of currency data
	 *
	 * @return the list of currency data
	 */
	public final List<CurrencyData> getCurrencyData() {
		return currencyData;
	}

	/**
	 * Set currency data list
	 *
	 * @param currencyD the currency data list
	 */
	public final void setCurrencyData(final List<CurrencyData> currencyD) {
		this.currencyData = currencyD;
	}

	/**
	 * Get parity
	 *
	 * @param currency the currency
	 * @return the parity
	 */
	public final Double getParity(final Currency currency) {
		Double res = 0d;
		for (CurrencyData currencyD : getCurrencyData()) {
			if (currencyD.getCurrency1() == currency) {
				res = currencyD.getValue();
				break;
			}
		}
		return res;
	}

	/**
	 * Get enum from str
	 *
	 * @param value the str value
	 * @return the currency
	 */
	public static Currency getEnum(final String value) {
		if (value == null) {
			throw new IllegalArgumentException();
		}
		for (Currency c : values()) {
			if (value.equalsIgnoreCase(c.getCode())) {
				return c;
			}
		}
		throw new IllegalArgumentException();
	}

	/**
	 * Get jsonobject
	 *
	 * @return the JSONObject
	 */
	public final JsonObject getJSONObject() {
		final JsonObject json = new JsonObject();
		json.addProperty("name", getName());
		json.addProperty("symbol", getSymbol());
		json.addProperty("code", getCode());
		return json;
	}

	/**
	 * List of currency data
	 **/
	private List<CurrencyData> currencyData;
	/**
	 * name
	 **/
	private final String name;
	/**
	 * symbol
	 **/
	private final String symbol;
	/**
	 * cod
	 **/
	private final String code;

} public class LoginException extends Exception {

	/** Serialization **/
	private static final long serialVersionUID = 5434242692908156608L;

	/**
	 * Constructor
	 *
	 * @param str
	 *            the error message
	 */
	public LoginException(final String str) {
		super(str);
	}

	/**
	 * Constructor
	 *
	 * @param str
	 *            the error message
	 * @param e
	 *            the exception
	 */
	public LoginException(final String str, final Exception e) {
		super(str, e);
	}
} public class NotFoundException extends RuntimeException {

	public NotFoundException(final int id) {
		super("Id not found: " + id);
	}

	public NotFoundException(final String ticker) {
		super("Ticker not found: " + ticker);
	}
} public class YahooException extends RuntimeException {

	/**
	 * Serialization
	 **/
	private static final long serialVersionUID = 1870609472239446880L;
	/**
	 * Error message
	 **/
	public static final String ERROR = "Yahoo result null. Table is probably locked.";
	/**
	 * Error message
	 **/
	private static final String CONNECT_ERROR = "Can't connect to yahoo website";
	/**
	 * Error message
	 **/
	private static final String ENCODE_ERROR = "Url encoding did not work";

	/**
	 * Constructor
	 *
	 * @param message the error message
	 */
	public YahooException(final String message) {
		super(message);
	}

	/**
	 * Constructor
	 *
	 * @param message the error message
	 * @param e       the exception
	 */
	public YahooException(final String message, final Exception e) {
		super(message, e);
	}

	public static YahooException encodeErrorException(final Exception exception) {
		return new YahooException(ENCODE_ERROR, exception);
	}

	public static YahooException cantConnectException(final Exception exception) {
		return new YahooException(CONNECT_ERROR, exception);
	}
} @RequiredArgsConstructor
@Component
public class AccountRepository implements DAO<Account> {

	private static final String INSERT = "fr.cph.stock.repository.AccountRepository.insertOneAccount";
	private static final String SELECT = "fr.cph.stock.repository.AccountRepository.selectOneAccount";
	private static final String UPDATE = "fr.cph.stock.repository.AccountRepository.updateOneAccount";
	private static final String DELETE = "fr.cph.stock.repository.AccountRepository.deleteOneAccount";

	@NonNull
	private final SqlSession session;

	@Override
	public void insert(final Account account) {
		session.insert(INSERT, account);
	}

	@Override
	public Optional<Account> select(final int id) {
		return Optional.ofNullable(session.selectOne(SELECT, id));
	}

	@Override
	public void update(final Account account) {
		session.update(UPDATE, account);
	}

	@Override
	public void delete(final Account account) {
		session.delete(DELETE, account);
	}
} @RequiredArgsConstructor
@Component
public class PortfolioRepository implements DAO<Portfolio> {

	private static final String INSERT = "fr.cph.stock.repository.PortfolioRepository.insertOnePortfolio";
	private static final String SELECT = "fr.cph.stock.repository.PortfolioRepository.selectOnePortfolio";
	private static final String UPDATE = "fr.cph.stock.repository.PortfolioRepository.updateOnePortfolio";
	private static final String DELETE = "fr.cph.stock.repository.PortfolioRepository.deleteOnePortfolio";
	private static final String SELECT_WITH_ID = "fr.cph.stock.repository.PortfolioRepository.selectPortfolioWithId";
	private static final String SELECT_EQUITY = "fr.cph.stock.repository.PortfolioRepository.selectEquityFromPortfolio";
	private static final String ACCOUNT_SELECT = "fr.cph.stock.repository.AccountRepository.selectAllAccountWithUserId";
	private static final String SHARE_VALUE_SELECT = "fr.cph.stock.repository.ShareValueRepository.selectAllValue";
	private static final String SHARE_VALUE_SELECT_FROM = "fr.cph.stock.repository.ShareValueRepository.selectShareValueFrom";
	private static final String SHARE_VALUE_SELECT_TO = "fr.cph.stock.repository.ShareValueRepository.selectShareValueFromTo";

	@NonNull
	private final SqlSession session;

	@Override
	public final void insert(final Portfolio portfolio) {
		session.insert(INSERT, portfolio);
	}

	@Override
	public final Optional<Portfolio> select(final int id) {
		return Optional.ofNullable(session.selectOne(SELECT, id));
	}

	@Override
	public final void update(final Portfolio portfolio) {
		session.update(UPDATE, portfolio);
	}

	@Override
	public final void delete(final Portfolio portfolio) {
		session.delete(DELETE, portfolio);
	}

	public final Optional<Portfolio> selectPortfolioFromUserIdWithEquities(final int userId, final Date from, final Date to) {
		Optional<Portfolio> portfolioOptional;
		portfolioOptional = Optional.ofNullable(session.selectOne(SELECT_WITH_ID, userId));
		portfolioOptional.ifPresent(portfolio -> {
			final List<Equity> equities = session.selectList(SELECT_EQUITY, portfolio.getId());
			portfolio.setEquities(equities);
			final List<Account> accounts = session.selectList(ACCOUNT_SELECT, userId);
			portfolio.setAccounts(accounts);
			if (from == null) {
				final List<ShareValue> shares = session.selectList(SHARE_VALUE_SELECT, userId);
				portfolio.setShareValues(shares);
			} else {
				final Map<String, Object> map = new HashMap<>();
				map.put("userId", userId);
				map.put("from", from);
				if (to == null) {
					final List<ShareValue> shares = session.selectList(SHARE_VALUE_SELECT_FROM, map);
					portfolio.setShareValues(shares);
				} else {
					map.put("to", to);
					final List<ShareValue> shares = session.selectList(SHARE_VALUE_SELECT_TO, map);
					portfolio.setShareValues(shares);
				}
			}
		});
		return portfolioOptional;
	}

	public final Optional<Portfolio> selectPortfolioFromUserIdWithEquities(final int userId) {
		return selectPortfolioFromUserIdWithEquities(userId, null, null);
	}
} @Mapper
@RequiredArgsConstructor
@Component
public class UserRepository implements DAO<User> {

	private static final String INSERT = "fr.cph.stock.repository.UserRepository.insertOneUser";
	private static final String SELECT = "fr.cph.stock.repository.UserRepository.selectOneUser";
	private static final String UPDATE = "fr.cph.stock.repository.UserRepository.updateOneUser";
	private static final String DELETE = "fr.cph.stock.repository.UserRepository.deleteOneUser";
	private static final String UPDATE_PASSWORD = "fr.cph.stock.repository.UserRepository.updateOneUserPassword";
	private static final String SELECT_WITH_LOGIN = "fr.cph.stock.repository.UserRepository.selectOneUserWithLogin";
	private static final String SELECT_WITH_EMAIL = "fr.cph.stock.repository.UserRepository.selectOneUserWithEmail";
	private static final String SELECT_ALL_USER = "fr.cph.stock.repository.UserRepository.selectAllUsers";

	@NonNull
	private final SqlSession session;

	@Override
	public final void insert(final User user) {
		session.insert(INSERT, user);
	}

	@Override
	public final Optional<User> select(final int id) {
		return Optional.ofNullable(session.selectOne(SELECT, id));
	}

	@Override
	public final void update(final User user) {
		session.update(UPDATE, user);
	}

	public final void updateOneUserPassword(final User user) {
		session.update(UPDATE_PASSWORD, user);
	}

	@Override
	public final void delete(final User user) {
		session.delete(DELETE, user);
	}

	public final Optional<User> selectWithLogin(final String login) {
		return Optional.ofNullable(session.selectOne(SELECT_WITH_LOGIN, login));
	}

	public final Optional<User> selectWithEmail(final String email) {
		return Optional.ofNullable(session.selectOne(SELECT_WITH_EMAIL, email));
	}

	public final List<User> selectAllUsers() {
		return session.selectList(SELECT_ALL_USER);
	}
} public interface SecurityService {

	String encodeToSha256(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException;

	String generateSalt() throws NoSuchAlgorithmException, UnsupportedEncodingException;
} public interface CurrencyService {

	/**
	 * Load a currency with its data
	 *
	 * @param currency the currency
	 * @return a currency
	 * @throws YahooException the yahoo exception
	 */
	Currency loadCurrencyData(Currency currency) throws YahooException;

	/**
	 * Update all current currencies
	 *
	 * @throws YahooException the yahoo exception
	 */
	void updateAllCurrencies() throws YahooException;

	/**
	 * Update one currency
	 *
	 * @param currency the currency
	 * @throws YahooException the yahoo exception
	 */
	void updateOneCurrency(Currency currency) throws YahooException;

	/**
	 * Get all currency data
	 *
	 * @param currency the currency
	 * @return a 2 dim array of object
	 */
	Object[][] getAllCurrencyData(Currency currency);
} public interface IndexService {

	/**
	 * @param yahooId the yahoo id
	 * @param from the from date
	 * @return a list of indexes
	 */
	List<Index> getIndexes(String yahooId, Date from);

	/**
	 * Get index information
	 *
	 * @param yahooId the yahoo id
	 * @param from    the from date
	 * @param to      the to date
	 * @return a list of indexes
	 */
	List<Index> getIndexes(String yahooId, Date from, Date to);

	/**
	 * Update an index
	 *
	 * @param yahooId the yahoo id
	 * @throws YahooException the yahoo exception
	 */
	void updateIndex(String yahooId) throws YahooException;

	/**
	 * Don't remember what it does
	 *
	 * @param yahooId  the yahoo id
	 * @param timeZone the timezone
	 * @throws YahooException the yahoo exception
	 */
	void checkUpdateIndex(String yahooId, TimeZone timeZone) throws YahooException;
} public interface UserService {

	void createUser(String login, String md5Password, String email) throws NoSuchAlgorithmException, UnsupportedEncodingException, LoginException;

	Optional<User> getUser(String login);

	Optional<User> getUserWithEmail(String email);

	Optional<User> checkUser(String login, String md5Password) throws LoginException;

	Optional<Portfolio> getUserPortfolio(int userId) throws YahooException;

	Optional<Portfolio> getUserPortfolio(int userId, Date from) throws YahooException;

	Optional<Portfolio> getUserPortfolio(int userId, Date from, Date to) throws YahooException;

	void validateUser(String login);

	void updateUser(User user);

	void updateOneUserPassword(User user);

	void updatePortfolio(Portfolio portfolio);

	void updateLiquidity(Account account, double liquidity);
} public enum Constants {
	;

	public static final String SP_500 = "^GSPC";
	public static final String CAC_40 = "^FCHI";


	public static final String APP_TITLE = "appTitle";
	public static final String AUTO_UPDATE = "autoUpdate";
	public static final String AUTO_UPDATE_EMAIL = "autoUpdateEmail";
	public static final String ACCOUNT = "account";
	public static final String ACCOUNT_ID = "accountId";
	public static final String ADD = "add";
	public static final String ADDED = "Added!";

	public static final String BUY = "buy";
	public static final String BEGIN = "begin";

	public static final String CHECK = "check";
	public static final String CHECKED = "checked";
	public static final String CURRENCIES = "currencies";
	public static final String CURRENCY = "currency";
	public static final String CURRENCY_2 = "currency2";
	public static final String CURRENCY_UPDATE = "currencyUpdate";
	public static final String CONSTANT_ADDED = "CONSTANT_ADDED";
	public static final String CONSTANT_MODIFIED = "CONSTANT_MODIFIED";
	public static final String CONSTANT_DELETED = "CONSTANT_DELETED";
	public static final String COMPANY_ID = "companyId";
	public static final String CAP_PIE = "capPie";
	public static final String COMMENTARY = "commentary";
	public static final String COMMENTARY_UPDATED = "commentaryUpdated";

	public static final String DATE_PATTERN = "datePattern";
	public static final String DAYS = "days";
	public static final String DELETE = "delete";
	public static final String DELETE_2 = "delete2";
	public static final String DELETE_FOLLOW_ID = "deleteFollowId";

	public static final String ERROR = "error";
	public static final String EMAIL = "email";
	public static final String ENGLISH = "English";
	public static final String END = "end";
	public static final String EQUITIES = "equities";

	public static final String FORMAT = "format";
	public static final String FRANCAIS = "Francais";
	public static final String FILE = "file";
	public static final String FROM = "from";
	public static final String FROM_UNDERSCORE = "_from";
	public static final String FOLLOWS = "follows";
	public static final String FUND = "Fund";

	public static final String HOME = "home";
	public static final String HOMEMOBILE = "homemobile";
	public static final String HIGHER = "higher";

	public static final String ID = "id";
	public static final String INDUSTRY_PERSONAL = "industryPersonal";

	public static final String LANGUAGE = "language";
	public static final String LOWER = "lower";
	public static final String LIQUIDITY = "liquidity";
	public static final String LIQUIDITY_MOVEMENT = "liquidityMovement";
	public static final String LOGIN = "login";
	public static final String LOCATION = "Location";

	public static final String MANUAL = "manual";
	public static final String MANUAL_NAME = "manualName";
	public static final String MANUAL_UNIT_COST_PRICE = "manualUnitCostPrice";
	public static final String MANUAL_QUANTITY = "manualQuantity";
	public static final String MANUAL_PARITY_PERSONAL = "manualParityPersonal";
	public static final String MANUAL_CURRENCY = "manualCurrency";
	public static final String MANUAL_INDUSTRY = "manualIndustry";
	public static final String MANUAL_SECTOR = "manualSector";
	public static final String MANUAL_QUOTE = "manualQuote";
	public static final String MESSAGE = "message";
	public static final String MAP_SECTOR = "mapSector";
	public static final String MAP_CAP = "mapCap";
	public static final String MODIFIED = "modified";
	public static final String MARKET_CAP_PERSONAL = "marketCapPersonal";
	public static final String MODIFY_PARITY_PERSONAL = "modifyParityPersonal";
	public static final String MODIFY_ERROR = "modifyError";
	public static final String MOD = "mod";
	public static final String MODIFIED_MESSAGE = "Modified!";
	public static final String MOVEMENT = "movement";

	public static final String NB_PAGE = "nbPage";
	public static final String NAME_PERSONAL = "namePersonal";

	public static final String OBJECTIVE = "objective";

	public static final String PASSWORD = "password";
	public static final String PARITY = "parity";
	public static final String PAGE = "page";
	public static final String PARITY_PERSONAL = "parityPersonal";
	public static final String PORTFOLIO = "portfolio";
	public static final String PDF = "pdf";

	public static final String STOP_LOSS = "stopLoss";
	public static final String SHARE_ID = "shareId";
	public static final String SELL = "sell";
	public static final String SECTOR_PERSONAL = "sectorPersonal";
	public static final String SECTOR_PIE = "sectorPie";
	public static final String SHARE_VALUE_PIE = "shareValuePie";
	public static final String SESSION = "session";

	public static final String TAXE = "taxe";
	public static final String TIME_ZONE = "timeZone";
	public static final String TAB = "tab";

	public static final String QUOTE = "quote";
	public static final String QUANTITY = "quantity";

	public static final String TICKER = "ticker";
	public static final String TO = "to";
	public static final String TO_UNDERSCORE = "_to";

	public static final String USER = "user";
	public static final String UPDATE = "update";
	public static final String UPDATED = "updated";
	public static final String UPDATE_TIME = "updateTime";
	public static final String UPDATE_STATUS = "updateStatus";
	public static final String UNIT_COST_PRICE = "unitCostPrice";
	public static final String UNKNOWN = "Unknown";

	public static final String WARN = "warn";

	public static final String YIELD = "yield";
	public static final String YIELD_1 = "yield1";
	public static final String YIELD_2 = "yield2";
	public static final String YIELD_PERSONAL = "yieldPersonal";
} public interface MailService {

	void sendMail(String emailSubjectTxt, String emailMsgTxt, String[] sendTo);
}
import fr.cph.stock.config.AppProperties;
import fr.cph.stock.entities.*;
import fr.cph.stock.enumtype.Currency;
import fr.cph.stock.exception.LoginException;
import fr.cph.stock.exception.NotFoundException;
import fr.cph.stock.exception.YahooException;
import fr.cph.stock.repository.AccountRepository;
import fr.cph.stock.repository.PortfolioRepository;
import fr.cph.stock.repository.UserRepository;
import fr.cph.stock.security.SecurityService;
import fr.cph.stock.service.CurrencyService;
import fr.cph.stock.service.IndexService;
import fr.cph.stock.service.UserService;
import fr.cph.stock.util.Constants;
import fr.cph.stock.util.mail.MailService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
 * Copyright 2017 Carl-Philipp Harmant
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.cph.stock.service.impl;



@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Component
@Log4j2
public class UserServiceImpl implements UserService {

	private static final MathContext MATHCONTEXT = MathContext.DECIMAL32;
	private static final int DB_PASSWORD_LIMIT = 64;

	@NonNull
	private final AppProperties appProperties;
	@NonNull
	private final CurrencyService currencyService;
	@NonNull
	private final SecurityService securityService;
	@NonNull
	private final IndexService indexService;
	@NonNull
	private final UserRepository userRepository;