/*
 *
 *  * Copyright (C) 2003-2016 eXo Platform SAS.
 *  *
 *  * This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Affero General Public License
 *  as published by the Free Software Foundation; either version 3
 *  of the License, or (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, see<http://www.gnu.org/licenses/>.
 *
 */
package org.exoplatform.cs.service;

import java.lang.reflect.Constructor;

import org.apache.commons.lang.StringUtils;
import org.jfree.util.Log;

import org.exoplatform.cs.dao.EnvironmentDAO;
import org.exoplatform.cs.dao.SpaceDAO;
import org.exoplatform.cs.dao.TopicDAO;
import org.exoplatform.cs.dao.TypeDAO;
import org.exoplatform.cs.dto.BrowserDTO;
import org.exoplatform.cs.dto.EnvironmentDTO;
import org.exoplatform.cs.entity.ASTypeEntity;
import org.exoplatform.cs.entity.DBTypeEntity;
import org.exoplatform.cs.entity.EnvTypeEntity;
import org.exoplatform.cs.entity.EnvironmentEntity;
import org.exoplatform.cs.entity.JVMTypeEntity;
import org.exoplatform.cs.entity.OSTypeEntity;
import org.exoplatform.cs.entity.SSOTypeEntity;
import org.exoplatform.cs.entity.SpaceEntity;
import org.exoplatform.cs.entity.TypeEntity;

/**
 * Created by The eXo Platform SAS
 * 
 * @author boubaker.khanfir@exoplatform.com
 * @since Apr 27, 2016
 */
public abstract class BaseService {
  protected EnvironmentDAO environmentDAO;

  protected SpaceDAO       spaceDAO;

  protected TopicDAO       topicDAO;

  protected TypeDAO        typeDAO;

  public BaseService(EnvironmentDAO environmentDAO, SpaceDAO spaceDAO, TopicDAO topicDAO, TypeDAO typeDAO) {
    this.environmentDAO = environmentDAO;
    this.spaceDAO = spaceDAO;
    this.topicDAO = topicDAO;
    this.typeDAO = typeDAO;
  }

  protected EnvironmentEntity convert(EnvironmentDTO dto, SpaceEntity spaceEntity, boolean remove) {
    EnvironmentEntity entity = new EnvironmentEntity();
    entity.setId(dto.getId());
    entity.setName(dto.getName());
    entity.setDefaultEnvironment(dto.isDefaultEnvironment());
    entity.setProductVersion(dto.getProductVersion());
    if (remove) {
      return entity;
    }

    if (dto.getAsId() > 0) {
      ASTypeEntity asTypeEntity = findType(dto.getAsId(), ASTypeEntity.class, false);
      entity.setAppServer(asTypeEntity);
    } else if (dto.getAsOtherId() > 0) {
      ASTypeEntity asTypeEntity = findType(dto.getAsOtherId(), ASTypeEntity.class, true);
      entity.setAppServer(asTypeEntity);
    } else {
      ASTypeEntity asTypeEntity = createType(dto.getAsOtherName(), ASTypeEntity.class, true);
      entity.setAppServer(asTypeEntity);
    }
    entity.setAsVersion(dto.getAsVersion());

    if (dto.getDbId() > 0) {
      DBTypeEntity dbTypeEntity = findType(dto.getDbId(), DBTypeEntity.class, false);
      entity.setRdbms(dbTypeEntity);
    } else if (dto.getDbOtherId() > 0) {
      DBTypeEntity dbTypeEntity = findType(dto.getDbOtherId(), DBTypeEntity.class, true);
      entity.setRdbms(dbTypeEntity);
    } else {
      DBTypeEntity dbTypeEntity = createType(dto.getDbOtherName(), DBTypeEntity.class, true);
      entity.setRdbms(dbTypeEntity);
    }

    entity.setDbVersion(dto.getDbVersion());
    entity.setDbEncoding(dto.getDbEncoding());

    if (dto.getJvmVendorId() > 0) {
      JVMTypeEntity jvmTypeEntity = findType(dto.getJvmVendorId(), JVMTypeEntity.class, false);
      entity.setJvmVendor(jvmTypeEntity);
    } else if (dto.getDbOtherId() > 0) {
      JVMTypeEntity jvmTypeEntity = findType(dto.getJvmVendorOtherId(), JVMTypeEntity.class, true);
      entity.setJvmVendor(jvmTypeEntity);
    } else {
      JVMTypeEntity jvmTypeEntity = createType(dto.getJvmVendorOtherName(), JVMTypeEntity.class, true);
      entity.setJvmVendor(jvmTypeEntity);
    }

    entity.setJvmVersion(dto.getJvmVersion());

    if (dto.getOsId() > 0) {
      OSTypeEntity osTypeEntity = findType(dto.getOsId(), OSTypeEntity.class, false);
      entity.setOs(osTypeEntity);
    } else if (dto.getDbOtherId() > 0) {
      OSTypeEntity osTypeEntity = findType(dto.getOsOtherId(), OSTypeEntity.class, true);
      entity.setOs(osTypeEntity);
    } else {
      OSTypeEntity osTypeEntity = createType(dto.getOsOtherName(), OSTypeEntity.class, true);
      entity.setOs(osTypeEntity);
    }

    entity.setOsVersion(dto.getOsVersion());

    if (dto.getSsoId() > 0) {
      SSOTypeEntity ssoTypeEntity = findType(dto.getSsoId(), SSOTypeEntity.class, false);
      entity.setSso(ssoTypeEntity);
    } else if (dto.getDbOtherId() > 0) {
      SSOTypeEntity ssoTypeEntity = findType(dto.getSsoOtherId(), SSOTypeEntity.class, true);
      entity.setSso(ssoTypeEntity);
    } else {
      SSOTypeEntity ssoTypeEntity = createType(dto.getSsoOtherName(), SSOTypeEntity.class, true);
      entity.setSso(ssoTypeEntity);
    }

    entity.setSsoVersion(dto.getSsoVersion());

    entity.setMoreInformation(dto.getMoreInformation());

    if (dto.getTypeId() > 0) {
      EnvTypeEntity envTypeEntity = findType(dto.getTypeId(), EnvTypeEntity.class, false);
      entity.setEnv(envTypeEntity);
    } else if (dto.getDbOtherId() > 0) {
      EnvTypeEntity envTypeEntity = findType(dto.getTypeOtherId(), EnvTypeEntity.class, true);
      entity.setEnv(envTypeEntity);
    } else {
      EnvTypeEntity envTypeEntity = createType(dto.getTypeOtherName(), EnvTypeEntity.class, true);
      entity.setEnv(envTypeEntity);
    }

    if (dto.getBrowsers() != null && !dto.getBrowsers().isEmpty()) {
      for (BrowserDTO browserDTO : dto.getBrowsers().values()) {
        if (browserDTO.isSelected()) {
          entity.getBrowsers().add(browserDTO.combinedName());
        }
      }
    }
    if (spaceEntity != null) {
      entity.setSpace(spaceEntity);
    } else if (!StringUtils.isBlank(dto.getSpaceGroupId())) {
      SpaceEntity space = spaceDAO.find(dto.getSpaceGroupId());
      if (space != null) {
        entity.setSpace(space);
      }
    }
    return entity;
  }

  private <T extends TypeEntity> T findType(long id, Class<T> typeClass, boolean other) {
    TypeEntity typeEntity = typeDAO.find(id);
    if (typeEntity == null) {
      return null;
    }
    if (typeClass.isInstance(typeEntity)) {
      return typeClass.cast(typeEntity);
    } else {
      throw new IllegalStateException("Entity with id '" + id + "' has different type, expected = " + typeClass + ", found = "
          + typeEntity.getClass() + ".");
    }
  }

  private <T extends TypeEntity> T createType(String name, Class<T> typeClass, boolean other) {
    TypeEntity typeEntity = null;
    if (typeEntity == null && !StringUtils.isBlank(name)) {
      try {
        Constructor<T> constructor = typeClass.getConstructor(Long.class, String.class, Boolean.class);
        typeEntity = constructor.newInstance(null, name, other);
        typeEntity = typeDAO.create(typeEntity);
      } catch (Exception e) {
        Log.error("Error while creating new entity of type '" + typeClass + "' with name " + name, e);
      }
    }
    return typeClass.cast(typeEntity);
  }

  protected EnvironmentDTO convert(EnvironmentEntity entity) {
    EnvironmentDTO dto = new EnvironmentDTO();
    dto.setId(entity.getId());
    dto.setName(entity.getName());
    dto.setDefaultEnvironment(entity.isDefaultEnvironment());
    dto.setProductVersion(entity.getProductVersion());
    if (entity.getAppServer() != null) {
      if (entity.getAppServer().getOther() == null || !entity.getAppServer().getOther()) {
        dto.setAsId(entity.getAppServer().getId());
        dto.setAsName(entity.getAppServer().getLabel());
      } else {
        dto.setAsId(-1);
        dto.setAsOtherId(entity.getAppServer().getId());
        dto.setAsOtherName(entity.getAppServer().getLabel());
      }
    }
    dto.setAsVersion(entity.getAsVersion());

    if (entity.getRdbms() != null) {
      if (entity.getRdbms().getOther() == null || !entity.getRdbms().getOther()) {
        dto.setDbId(entity.getRdbms().getId());
        dto.setDbName(entity.getRdbms().getLabel());
      } else {
        dto.setDbId(-1);
        dto.setDbOtherId(entity.getRdbms().getId());
        dto.setDbOtherName(entity.getRdbms().getLabel());
      }
    }
    dto.setDbEncoding(entity.getDbEncoding());
    dto.setDbVersion(entity.getDbVersion());

    if (entity.getJvmVendor() != null) {
      if (entity.getJvmVendor().getOther() == null || !entity.getJvmVendor().getOther()) {
        dto.setJvmVendorId(entity.getJvmVendor().getId());
        dto.setJvmVendorName(entity.getJvmVendor().getLabel());
      } else {
        dto.setJvmVendorId(-1);
        dto.setJvmVendorOtherId(entity.getJvmVendor().getId());
        dto.setJvmVendorOtherName(entity.getJvmVendor().getLabel());
      }
    }
    dto.setJvmVersion(entity.getJvmVersion());

    if (entity.getOs() != null) {
      if (entity.getOs().getOther() == null || !entity.getOs().getOther()) {
        dto.setOsId(entity.getOs().getId());
        dto.setOsName(entity.getOs().getLabel());
      } else {
        dto.setOsId(-1);
        dto.setOsOtherId(entity.getOs().getId());
        dto.setOsOtherName(entity.getOs().getLabel());
      }
    }
    dto.setOsVersion(entity.getOsVersion());

    if (entity.getSso() != null) {
      if (entity.getSso().getOther() == null || !entity.getSso().getOther()) {
        dto.setSsoId(entity.getSso().getId());
        dto.setSsoName(entity.getSso().getLabel());
      } else {
        dto.setSsoId(-1);
        dto.setSsoOtherId(entity.getSso().getId());
        dto.setSsoOtherName(entity.getSso().getLabel());
      }
    }
    dto.setSsoVersion(entity.getSsoVersion());

    dto.setMoreInformation(entity.getMoreInformation());

    if (entity.getEnv() != null) {
      if (entity.getEnv().getOther() == null || !entity.getEnv().getOther()) {
        dto.setTypeId(entity.getEnv().getId());
        dto.setTypeName(entity.getEnv().getLabel());
      } else {
        dto.setTypeId(-1);
        dto.setTypeOtherId(entity.getEnv().getId());
        dto.setTypeOtherName(entity.getEnv().getLabel());
      }
    }

    if (entity.getBrowsers() != null && !entity.getBrowsers().isEmpty()) {
      for (String browserNameAndVersion : entity.getBrowsers()) {
        BrowserDTO browserDTO = new BrowserDTO(browserNameAndVersion, true);
        dto.getBrowsers().put(browserDTO.getName().name(), browserDTO);
      }
    }
    dto.setSpaceGroupId(entity.getSpace() == null ? null : entity.getSpace().getGroupId());
    return dto;
  }
}
