/*
 * Copyright 2011 Federal Chancellery Austria and
 * Graz University of Technology
 * 
 * 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
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * 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 at.gv.util.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.gv.util.MiscUtil;
import at.gv.util.ssl.JaxWsSSLConfiguration;
import at.gv.util.ssl.JaxWsSSLConfigurationPropertiesImpl;
import at.gv.util.xsd.szr.pvp.Param;
import at.gv.util.xsd.szr.pvp.PvpTokenType;
import at.gv.util.xsd.szr.pvp.PvpTokenType.Accounting;
import at.gv.util.xsd.szr.pvp.PvpTokenType.Accounting.GvCostCenterId;
import at.gv.util.xsd.szr.pvp.PvpTokenType.Authenticate;
import at.gv.util.xsd.szr.pvp.PvpTokenType.Authenticate.UserPrincipal;
import at.gv.util.xsd.szr.pvp.PvpTokenType.Authorize;
import at.gv.util.xsd.szr.pvp.Role;

/**
 * ZUSE-Util configuration implementation based on Java properties.
 * 
 * @author <a href="mailto:Arne.Tauber@egiz.gv.at">Arne Tauber</a>
 *
 */
public class EgovUtilPropertiesConfiguration implements EgovUtilConfiguration {

	Logger log = LoggerFactory.getLogger(EgovUtilPropertiesConfiguration.class);
	
	private Properties props;
	private String configDir = null;
	private JaxWsSSLConfigurationPropertiesImpl moaSPSSsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl moaIDsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl moaZSsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl szrsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl ursslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl missslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl mmssslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl uspsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl clearingsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl storkMISsslConfiguration = null;
	private JaxWsSSLConfigurationPropertiesImpl ersbsslConfiguration = null;
	
	public EgovUtilPropertiesConfiguration(String propertiesFileName) throws IOException {
		if (propertiesFileName == null) {
			throw new NullPointerException("Parameter propertiesFile must not be null.");
		}
		File propertiesFile = new File(propertiesFileName);
		FileInputStream fis = new FileInputStream(propertiesFile);
		this.configDir = propertiesFile.getParentFile().getAbsolutePath();
		log.trace("EgovUtil Configuration directory: " + this.configDir);
		this.props = new Properties();
		props.load(fis);
		
		initialize();
	}
	
	public EgovUtilPropertiesConfiguration(Properties props, String configDir) {
		if (props == null) {
			throw new NullPointerException("Parameter props must not be null.");
		}
		if (configDir == null) {
			throw new NullPointerException("Argument 'configDir' must not be null.");
		}
		this.configDir = configDir;
		this.props = props;
		
		initialize();
	}

	private void initialize() {
		 moaSPSSsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.moaspss"); 
		 moaIDsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.moaid");
		 moaZSsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.moazs");
		 szrsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.szr");
		 ursslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.ur");
		 missslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.mis");
		 mmssslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.mms");
		 clearingsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.zuserech");
		 uspsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.usp");
		 storkMISsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.misstork");
		 ersbsslConfiguration = new JaxWsSSLConfigurationPropertiesImpl(this.props, this.configDir, "egovutil.ersb");
	}
	

	@Override
	public String getConfigurationValue(String key) {
		return this.props.getProperty(key);
		
	}

	@Override
	public String getConfigurationValue(String key, String defaultValue) {
		return this.props.getProperty(key, defaultValue);
		
	}	
	
  public JaxWsSSLConfiguration getMOASPSSsslConfiguration() {
	  return moaSPSSsslConfiguration;
  }

  public JaxWsSSLConfiguration getMOAIDsslConfiguration() {
	  return moaIDsslConfiguration;
  }


  public JaxWsSSLConfiguration getSZRsslConfiguration() {
	  return szrsslConfiguration;
  }
	

  public JaxWsSSLConfiguration getURsslConfiguration() {
	  return ursslConfiguration;
  }

  public JaxWsSSLConfiguration getMISSTORKsslConfiguration() {
	  return storkMISsslConfiguration;
  }
  
  public boolean isMISSTORKEnvironment() {
	try {
	  	return Boolean.parseBoolean(this.props.getProperty("egovutil.misstork.test"));
		  	
	} catch(Exception e) {
		return false;
	}
  }

  public String getMISSTORKProductionEnvironmentURL() {
	  return this.props.getProperty("egovutil.misstork.prod.url");
  }

  public String getMISSTORKTestEnvironmentURL() {
	  return this.props.getProperty("egovutil.misstork.test.url");
  }
	
  public boolean isSZRTestEnvironment() {
		try {
	  	return Boolean.parseBoolean(this.props.getProperty("egovutil.szr.test"));
		} catch(Exception e) {
			return false;
		}
  }
	

  public boolean isURTestEnvironment() {
		try {
	  	return Boolean.parseBoolean(this.props.getProperty("egovutil.ur.test"));
		} catch(Exception e) {
			return false;
		}
  }


  public PvpTokenType getPVPToken() {
		return getPVPToken("szr");
	}
	

  public PvpTokenType getURPVPToken() {
		return getPVPToken("ur");
	}
	
  public PvpTokenType getPVPToken(String prefix) {
	  PvpTokenType token = new PvpTokenType();
	  // set version
	  String version = props.getProperty("egovutil." + prefix + ".token.version");
	  MiscUtil.assertNotNull(version, "PVP version in configuration");
	  
	  // read other information
	  String participantId = props.getProperty("egovutil." + prefix + ".token.participantid");
	  MiscUtil.assertNotNull(participantId, "Participant ID in configuration");
	  
	  String gvOuDomain = props.getProperty("egovutil." + prefix + ".token.gvoudomain");
	  MiscUtil.assertNotNull(gvOuDomain, "GvOuDomain in configuration");
	  
	  String userId = props.getProperty("egovutil." + prefix + ".token.userid");
	  MiscUtil.assertNotNull(userId, "User ID in configuration");
	  
	  String cn = props.getProperty("egovutil." + prefix + ".token.cn");
	  MiscUtil.assertNotNull(cn, "CN in configuration");
	  
	  String gvOuId = props.getProperty("egovutil." + prefix + ".token.gvouid");
	  MiscUtil.assertNotNull(gvOuId, "GvOuId in configuration");
	  
	  String ou = props.getProperty("egovutil." + prefix + ".token.ou");
	  MiscUtil.assertNotNull(ou, "GvOuId in configuration");
	  
	  String secClassString = props.getProperty("egovutil." + prefix + ".token.gvsecclass");
	  MiscUtil.assertNotNull(secClassString, "SecClass in configuration");
	  BigInteger secClass = new BigInteger(secClassString);
	  
	  String gvGid = props.getProperty("egovutil." + prefix + ".token.gvgid");
	  MiscUtil.assertNotNull(gvGid, "GvGid in configuration");
	  
	  String gvFunction = props.getProperty("egovutil." + prefix + ".token.gvfunction");
	  MiscUtil.assertNotNull(gvFunction, "GvFunction in configuration");
	  
	  String roleString = props.getProperty("egovutil." + prefix + ".roles");
	  MiscUtil.assertNotNull(roleString, "Roles in configuration");
	  
	  String[] roles = roleString.split(",");
	  
	  String costCenterId = props.getProperty("egovutil." + prefix + ".token.costCenterId");	  
	  String invoiceRecptId = props.getProperty("egovutil." + prefix + ".token.invoiceRecptId");
	  
	  token.setVersion(version);
	  
	  // create authentication information
	  Authenticate authenticate = new Authenticate();
	  authenticate.setParticipantId(participantId);
	  authenticate.setGvOuDomain(gvOuDomain);
	  token.setAuthenticate(authenticate);
	  
	  //set UserPrincipal
	  UserPrincipal up = new UserPrincipal();
	  up.setCn(cn);
	  up.setGvFunction(gvFunction);
	  up.setGvGid(gvGid);
	  up.setGvOuId(gvOuId);
	  up.setGvSecClass(secClass);
	  up.setOu(ou);
	  up.setUserId(userId);
	  authenticate.setUserPrincipal(up);
	
	  //set Accountuing information
	  if (MiscUtil.isNotEmpty(invoiceRecptId) || MiscUtil.isNotEmpty(costCenterId)) {
		  Accounting accounting = new Accounting();
		  accounting.setInvoiceRecptId(invoiceRecptId);
		  
		  if (MiscUtil.isNotEmpty(costCenterId)) {
			  List<GvCostCenterId> gvCostCenterId = accounting.getGvCostCenterId();
			  String[] costCenterIdList = costCenterId.split(",");
			  for (String el : costCenterIdList) {
				  GvCostCenterId id = new GvCostCenterId();
				  id.setValue(el);
				  
				  //first element is marked as 'Default'
				  if (gvCostCenterId.isEmpty())
					  id.setDefault(true);
				  gvCostCenterId.add(id);
				  
			  }
		  		  
		  }
		  token.setAccounting(accounting);
		  
	  }
		
		// set roles
		Authorize authorize = new Authorize();
		
		for (String cRole : roles) {
			//split role parameters
			String roleValue = null;
			Map<String, String> roleparam = new HashMap<String, String>();
			if (cRole.contains("(")) {
				roleValue = cRole.substring(0, cRole.indexOf("("));
				String[] roleParams = cRole.substring(cRole.indexOf("(") + 1, cRole.length()-1).split(",");
				for(String param: roleParams) {
					String[] values = param.split("=");
					if ((values.length % 2) != 0)
						throw new NullPointerException("RoleAttributes has no valid format");
					
					roleparam.put(values[0], values[1]);
				}
				
			} else {
				roleValue = cRole;
			}
			
			Role role = new Role();
			role.setValue(roleValue);
			
			if (!roleparam.isEmpty()) {
				List<Param> params = role.getParam();
				if (params == null)
					params = new ArrayList<Param>();
				
				Set<String> entryset = roleparam.keySet();
				for (String entry : entryset) {
					Param param = new Param();
					param.setKey(entry);
					param.setValue(roleparam.get(entry));
					params.add(param);
				}
			}
			
			role.setDummy(null);
			authorize.getRole().add(role);
		}
		token.setAuthorize(authorize);
	  return token;
  }

	
  public String getSZRProductionEnvironmentURL() {
	  return this.props.getProperty("egovutil.szr.prod.url");
  }

	
  public String getSZRTestEnvironmentURL() {
		return this.props.getProperty("egovutil.szr.test.url");
  }
	
	
  public String getURProductionEnvironmentURL() {
	  return this.props.getProperty("egovutil.ur.prod.url");
  }

	
  public String getURTestEnvironmentURL() {
		return this.props.getProperty("egovutil.ur.test.url");
  }

  public String getURSecondaryProductionEnvironmentURL() {
	  return this.props.getProperty("egovutil.ur.prod.secondary.url");
  }
	
  public JaxWsSSLConfiguration getMISsslConfiguration() {
	  return missslConfiguration;
  }

	
  public JaxWsSSLConfiguration getMMSsslConfiguration() {
	  return mmssslConfiguration;
  }

	
  public JaxWsSSLConfiguration getMOAZSsslConfiguration() {
	  return moaZSsslConfiguration;
  }

	
  public JaxWsSSLConfiguration getClearingsslConfiguration() {
	  return clearingsslConfiguration;
  }


  public boolean isUSPTestEnvironment() {
		try {
	  	return Boolean.parseBoolean(this.props.getProperty("egovutil.usp.test"));
		} catch(Exception e) {
			return false;
		}
  }


  public String getUSPTestEnvironmentURL() {
		return this.props.getProperty("egovutil.usp.test.url");
  }


  public String getUSPProductionEnvironmentURL() {
		return this.props.getProperty("egovutil.usp.prod.url");
  }


  public String getUSPApplicationId() {
		return this.props.getProperty("egovutil.usp.appid");
  }


  public JaxWsSSLConfiguration getUSPsslConfiguration() {
	  return uspsslConfiguration;
  }

  public PvpTokenType getUSPPVPToken() {
		return getPVPToken("usp");
  }

  public int getHTTPRequestTimeout() {
	  return Integer.parseInt(this.props.getProperty("egovutil.http.timeout","60000"));
  }
  
  public JaxWsSSLConfiguration getERsBsslConfiguration() {
	  return ersbsslConfiguration;
  }
		  
		
  public boolean isERsBTestEnvironment() {
	  try {
		  	return Boolean.parseBoolean(this.props.getProperty("egovutil.ersb.test"));
			  	
	  } catch(Exception e) {
				return false;
	  }
  }
		
  public PvpTokenType getERsBPVPToken() {
	  return getPVPToken("ersb");
  }
			
  public String getERsBProductionEnvironmentURL() {
	  return this.props.getProperty("egovutil.ersb.prod.url");
  }

  public String getERsBTestEnvironmentURL() {
	  return this.props.getProperty("egovutil.ersb.test.url");
  }
	
}