/*
 * Copyright © 2015 <code@io7m.com> http://io7m.com
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package com.io7m.jranges;

import com.io7m.junreachable.UnreachableCodeException;

import java.math.BigInteger;
import java.util.Objects;

/**
 * <p> Functions for enforcing range constraints at run time. </p> <p> The
 * functions are intended for use in the manner of assertions. That is, the program should behave
 * identically if all of the checks are removed. The functions raise {@link RangeCheckException}
 * upon failure. Exceptions of this type are <i>not</i> intended to be caught and handled; they
 * indicate program bugs. </p>
 *
 * @see RangeCheckException
 */

public final class RangeCheck
{
  private RangeCheck()
  {
    throw new UnreachableCodeException();
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than {@code
   * in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of the checked value
   * @param lower_name The name of the lower bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static long checkGreaterLong(
    final long x,
    final String x_name,
    final long in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x > in_lower) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) <= %s (%d)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than {@code
   * in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of the checked value
   * @param lower_name The name of the lower bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static int checkGreaterInteger(
    final int x,
    final String x_name,
    final int in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x > in_lower) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) <= %s (%d)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than {@code
   * in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of the checked value
   * @param lower_name The name of the lower bound
   *
   * @return x
   */

  public static BigInteger checkGreaterBig(
    final BigInteger x,
    final String x_name,
    final BigInteger in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x, "Value");
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(in_lower, "Lower");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x.compareTo(in_lower) > 0) {
      return x;
    }

    final var message =
      String.format("%s (%s) <= %s (%s)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than {@code
   * in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of the checked value
   * @param lower_name The name of the lower bound
   *
   * @return x
   */

  public static double checkGreaterDouble(
    final double x,
    final String x_name,
    final double in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x > in_lower) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%f) <= %s (%f)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than or equal
   * to {@code in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of x
   * @param lower_name The name of the lower bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static long checkGreaterEqualLong(
    final long x,
    final String x_name,
    final long in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x >= in_lower) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) < %s (%d)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than or equal
   * to {@code in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of x
   * @param lower_name The name of the lower bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static int checkGreaterEqualInteger(
    final int x,
    final String x_name,
    final int in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x >= in_lower) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) < %s (%d)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than or equal
   * to {@code in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of the checked value
   * @param lower_name The name of the lower bound
   *
   * @return x
   */

  public static BigInteger checkGreaterEqualBig(
    final BigInteger x,
    final String x_name,
    final BigInteger in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x, "Value");
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(in_lower, "Lower");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x.compareTo(in_lower) >= 0) {
      return x;
    }

    final var message =
      String.format("%s (%s) < %s (%s)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is greater than or equal
   * to {@code in_lower} (named {@code lower_name}). </p>
   *
   * @param x          The checked value
   * @param in_lower   The lower bound
   * @param x_name     The name of x
   * @param lower_name The name of the lower bound
   *
   * @return x
   */

  public static double checkGreaterEqualDouble(
    final double x,
    final String x_name,
    final double in_lower,
    final String lower_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(lower_name, "Lower bound name");

    if (x >= in_lower) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%f) < %s (%f)", x_name, x, lower_name, in_lower);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is included in the given
   * range {@code range} (named {@code range_name}). </p>
   *
   * @param x          The checked value
   * @param x_name     The name of the checked value
   * @param range      The inclusive range
   * @param range_name The name of the inclusive range
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static long checkIncludedInLong(
    final long x,
    final String x_name,
    final RangeInclusiveL range,
    final String range_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(range, "Range");
    Objects.requireNonNull(range_name, "Range name");

    if (range.includesValue(x)) {
      return x;
    }

    final var message = String.format(
      "%s <= %s (%s) <= %s (%s) == false",
      Long.valueOf(range.lower()),
      x_name,
      Long.valueOf(x),
      Long.valueOf(range.upper()),
      range_name);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is included in the given
   * range {@code range} (named {@code range_name}). </p>
   *
   * @param x          The checked value
   * @param x_name     The name of the checked value
   * @param range      The inclusive range
   * @param range_name The name of the inclusive range
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static int checkIncludedInInteger(
    final int x,
    final String x_name,
    final RangeInclusiveI range,
    final String range_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(range, "Range");
    Objects.requireNonNull(range_name, "Range name");

    if (range.includesValue(x)) {
      return x;
    }

    final var message = String.format(
      "%s <= %s (%s) <= %s (%s) == false",
      Integer.valueOf(range.lower()),
      x_name,
      Integer.valueOf(x),
      Integer.valueOf(range.upper()),
      range_name);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is included in the given
   * range {@code range} (named {@code range_name}). </p>
   *
   * @param x          The checked value
   * @param x_name     The name of the checked value
   * @param range      The inclusive range
   * @param range_name The name of the inclusive range
   *
   * @return x
   */

  public static BigInteger checkIncludedInBig(
    final BigInteger x,
    final String x_name,
    final RangeInclusiveB range,
    final String range_name)
  {
    Objects.requireNonNull(x, "Value");
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(range, "Range");
    Objects.requireNonNull(range_name, "Range name");

    if (range.includesValue(x)) {
      return x;
    }

    final var message = String.format(
      "%s <= %s (%s) <= %s (%s) == false",
      range.lower(),
      x_name,
      x,
      range.upper(),
      range_name);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than {@code
   * in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of the checked value
   * @param upper_name The name of the upper bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static long checkLessLong(
    final long x,
    final String x_name,
    final long in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x < in_upper) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) >= %s (%d)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than {@code
   * in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of the checked value
   * @param upper_name The name of the upper bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static int checkLessInteger(
    final int x,
    final String x_name,
    final int in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x < in_upper) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) >= %s (%d)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than {@code
   * in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of the checked value
   * @param upper_name The name of the upper bound
   *
   * @return x
   */

  public static BigInteger checkLessBig(
    final BigInteger x,
    final String x_name,
    final BigInteger in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x, "Value");
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(in_upper, "Upper");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x.compareTo(in_upper) < 0) {
      return x;
    }

    final var message =
      String.format("%s (%s) >= %s (%s)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than {@code
   * in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of the checked value
   * @param upper_name The name of the upper bound
   *
   * @return x
   */

  public static double checkLessDouble(
    final double x,
    final String x_name,
    final double in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x < in_upper) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%f) >= %s (%f)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than or equal to
   * {@code in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of x
   * @param upper_name The name of the upper bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static long checkLessEqualLong(
    final long x,
    final String x_name,
    final long in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x <= in_upper) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) > %s (%d)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than or equal to
   * {@code in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of x
   * @param upper_name The name of the upper bound
   *
   * @return x
   *
   * @since 2.0.0
   */

  public static int checkLessEqualInteger(
    final int x,
    final String x_name,
    final int in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x <= in_upper) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%d) > %s (%d)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than or equal to
   * {@code in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of the checked value
   * @param upper_name The name of the upper bound
   *
   * @return x
   */

  public static BigInteger checkLessEqualBig(
    final BigInteger x,
    final String x_name,
    final BigInteger in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x, "Value");
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(in_upper, "Upper");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x.compareTo(in_upper) <= 0) {
      return x;
    }

    final var message =
      String.format("%s (%s) > %s (%s)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code x} (named {@code x_name}) is less than or equal to
   * {@code in_upper} (named {@code upper_name}). </p>
   *
   * @param x          The checked value
   * @param in_upper   The upper bound
   * @param x_name     The name of x
   * @param upper_name The name of the upper bound
   *
   * @return x
   */

  public static double checkLessEqualDouble(
    final double x,
    final String x_name,
    final double in_upper,
    final String upper_name)
  {
    Objects.requireNonNull(x_name, "Value name");
    Objects.requireNonNull(upper_name, "Upper bound name");

    if (x <= in_upper) {
      return x;
    }

    @SuppressWarnings("boxing") final var message =
      String.format("%s (%f) > %s (%f)", x_name, x, upper_name, in_upper);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code inner} (named {@code inner_name}) is included in the
   * given range {@code outer} (named {@code outer_name}). </p>
   *
   * @param inner      The checked range
   * @param inner_name The name of the checked range
   * @param outer      The outer range
   * @param outer_name The name of the outer range
   *
   * @return inner
   *
   * @since 2.0.0
   */

  public static RangeInclusiveL checkRangeIncludedInLong(
    final RangeInclusiveL inner,
    final String inner_name,
    final RangeInclusiveL outer,
    final String outer_name)
  {
    Objects.requireNonNull(inner, "Inner range");
    Objects.requireNonNull(inner_name, "Inner range name");
    Objects.requireNonNull(outer, "Outer range");
    Objects.requireNonNull(outer_name, "Outer range name");

    if (inner.isIncludedIn(outer)) {
      return inner;
    }

    final var message = String.format(
      "Inner range %s (%s) not included in outer range %s (%s)",
      inner_name,
      inner,
      outer_name,
      outer);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code inner} (named {@code inner_name}) is included in the
   * given range {@code outer} (named {@code outer_name}). </p>
   *
   * @param inner      The checked range
   * @param inner_name The name of the checked range
   * @param outer      The outer range
   * @param outer_name The name of the outer range
   *
   * @return inner
   *
   * @since 2.0.0
   */

  public static RangeInclusiveI checkRangeIncludedInInteger(
    final RangeInclusiveI inner,
    final String inner_name,
    final RangeInclusiveI outer,
    final String outer_name)
  {
    Objects.requireNonNull(inner, "Inner range");
    Objects.requireNonNull(inner_name, "Inner range name");
    Objects.requireNonNull(outer, "Outer range");
    Objects.requireNonNull(outer_name, "Outer range name");

    if (inner.isIncludedIn(outer)) {
      return inner;
    }

    final var message = String.format(
      "Inner range %s (%s) not included in outer range %s (%s)",
      inner_name,
      inner,
      outer_name,
      outer);

    throw new RangeCheckException(message);
  }

  /**
   * <p> Assert that {@code inner} (named {@code inner_name}) is included in the
   * given range {@code outer} (named {@code outer_name}). </p>
   *
   * @param inner      The checked range
   * @param inner_name The name of the checked range
   * @param outer      The outer range
   * @param outer_name The name of the outer range
   *
   * @return inner
   */

  public static RangeInclusiveB checkRangeIncludedInBig(
    final RangeInclusiveB inner,
    final String inner_name,
    final RangeInclusiveB outer,
    final String outer_name)
  {
    Objects.requireNonNull(inner, "Inner range");
    Objects.requireNonNull(inner_name, "Inner range name");
    Objects.requireNonNull(outer, "Outer range");
    Objects.requireNonNull(outer_name, "Outer range name");

    if (inner.isIncludedIn(outer)) {
      return inner;
    }

    final var message = String.format(
      "Inner range %s (%s) not included in outer range %s (%s)",
      inner_name,
      inner,
      outer_name,
      outer);

    throw new RangeCheckException(message);
  }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 net.sourceforge.javydreamercsw.validation.manager.web.service;

import com.validation.manager.core.DataBaseManager;
import com.validation.manager.core.VMException;
import com.validation.manager.core.db.Project;
import com.validation.manager.core.db.VmUser;
import com.validation.manager.core.db.controller.ProjectJpaController;
import com.validation.manager.core.server.core.ProjectServer;
import com.validation.manager.core.tool.MD5;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
@WebService(serviceName = "VMWebService")
public class VMWebService {

    private final Map<String, Object> parameters = new HashMap<>();
    private static final Logger LOG
            = Logger.getLogger(VMWebService.class.getName());

    /**
     * Web service operation
     *
     * @param username Username
     * @param password Password
     * @return User with provided credentials or null if invalid.
     * @throws com.validation.manager.core.VMException
     */
    @WebMethod(operationName = "getVMUser")
    public VmUser getVMUser(@WebParam(name = "user") final String username,
            @WebParam(name = "pass") final String password) throws VMException {
        VmUser user = isValidUser(username, password);
        if (user == null) {
            throw new VMException("Invalid username and/or password!");
        }
        return user;
    }

    private VmUser isValidUser(String username, String password) {
        VmUser user = null;
        parameters.clear();
        parameters.put("username", username);
        List<Object> result
                = DataBaseManager.namedQuery("VmUser.findByUsername",
                        parameters);
        if (result != null) {
            for (Object obj : result) {
                if (obj instanceof VmUser) {
                    try {
                        VmUser vmuser = (VmUser) obj;
                        if (vmuser.getPassword().equals(MD5.encrypt(password))) {
                            user = vmuser;
                        }
                    } catch (Exception ex) {
                        LOG.log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
        return user;
    }

    /**
     * Web service operation
     *
     * @param project Project to retrieve
     * @param user User requesting the information.
     * @return Update project.
     * @throws com.validation.manager.core.VMException
     */
    @WebMethod(operationName = "getProject")
    public Project getProject(@WebParam(name = "project") final Project project,
            @WebParam(name = "user") final VmUser user) throws VMException {
        Project p = null;
        if (isValidUser(user.getUsername(), user.getPassword()) != null) {
            p = new ProjectServer(project).getEntity();
        }
        return p;
    }

    /**
     * Web service operation
     *
     * @param user User requesting the information.
     * @return List of root projects.
     * @throws com.validation.manager.core.VMException
     */
    @WebMethod(operationName = "getRootProjects")
    public List<Project> getRootProjects(@WebParam(name = "user") final VmUser user)
            throws VMException {
        List<Project> projects = new ArrayList<>();
        if (isValidUser(user.getUsername(), user.getPassword()) != null) {
            ProjectJpaController controller
                    = new ProjectJpaController(DataBaseManager
                            .getEntityManagerFactory());
            controller.findProjectEntities().stream().filter((p)
                    -> (p.getParentProjectId() == null)).forEachOrdered((p) -> {
                projects.add(p);
            });
        }
        return projects;
    }

    /**
     * Web service operation
     *
     * @param newProject Project to save.
     * @param user User requesting the information.
     * @return true if successful, false otherwise.
     * @throws com.validation.manager.core.VMException
     */
    @WebMethod(operationName = "saveProject")
    public boolean saveProject(@WebParam(name = "newProject") final Project newProject,
            @WebParam(name = "user") final VmUser user) throws VMException {
        boolean result = false;
        if (isValidUser(user.getUsername(), user.getPassword()) != null) {
            ProjectServer ps = new ProjectServer(newProject);
            ps.copy(newProject);
            result = true;
        }
        return result;
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.history;

import com.validation.manager.core.DataBaseManager;
import com.validation.manager.core.EntityServer;
import com.validation.manager.core.db.FieldType;
import com.validation.manager.core.db.History;
import com.validation.manager.core.db.HistoryField;
import com.validation.manager.core.db.VmUser;
import com.validation.manager.core.db.controller.VmUserJpaController;
import com.validation.manager.core.server.core.FieldTypeServer;
import com.validation.manager.core.server.core.HistoryFieldServer;
import com.validation.manager.core.server.core.HistoryServer;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.openide.util.Exceptions;

@MappedSuperclass
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "VERSIONABLE_TYPE")
public abstract class Versionable implements Comparable<Versionable>,
        Serializable {

    private static final Logger LOG
            = Logger.getLogger(Versionable.class.getSimpleName());

    @Column(name = "majorVersion", insertable = false, updatable = false)
    private Integer majorVersion = 0;
    @Column(name = "midVersion", insertable = false, updatable = false)
    private Integer midVersion = 0;
    @Column(name = "minorVersion", insertable = false, updatable = false)
    private Integer minorVersion = 1;
    @Column(name = "reason", insertable = false, updatable = false)
    private String reason;
    @Column(name = "modifierId", insertable = false, updatable = false)
    private int modifierId = -1;
    @Column(name = "modificationTime", insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date modificationTime;
    @Column(name = "dirty")
    @Basic(optional = false)
    private boolean dirty = false;

    public int getModifierId() {
        return modifierId;
    }

    public void setModifierId(int modifierId) {
        this.modifierId = modifierId;
    }

    public Integer getMajorVersion() {
        return this.majorVersion;
    }

    public void setMajorVersion(Integer majorVersion) {
        this.majorVersion = majorVersion;
    }

    public Integer getMidVersion() {
        return this.midVersion;
    }

    public void setMidVersion(Integer midVersion) {
        this.midVersion = midVersion;
    }

    public Integer getMinorVersion() {
        return this.minorVersion;
    }

    public void setMinorVersion(Integer minorVersion) {
        this.minorVersion = minorVersion;
    }

    public String getReason() {
        return this.reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public Date getModificationTime() {
        return this.modificationTime;
    }

    public void setModificationTime(Date modificationTime) {
        this.modificationTime = modificationTime;
    }

    public boolean getDirty() {
        return this.dirty;
    }

    /**
     * @param dirty the dirty to set
     */
    public void setDirty(boolean dirty) {
        this.dirty = dirty;
    }

    private void updateInternalHistory() throws Exception {
        if (this instanceof EntityServer) {
            EntityServer vs = (EntityServer) this;
            //Copy the version changes
            Versionable ao = (Versionable) vs.getEntity();
            ao.update(ao, this);
            updateHistory(ao);
            vs.write2DB();
        } else {
            updateHistory();
            try {
                DataBaseManager.getEntityManagerFactory().getMetamodel()
                        .entity(this.getClass());
                Object key = DataBaseManager.getEntityManagerFactory()
                        .getPersistenceUnitUtil().getIdentifier(this);
                if (key != null
                        && DataBaseManager.getEntityManager()
                                .find(this.getClass(), key) != null) {
                    DataBaseManager.getEntityManager().merge(this);
                }
            }
            catch (IllegalArgumentException ex) {
                LOG.log(Level.SEVERE, "Ignore if this is an Unit test!", ex);
            }
        }
    }

    /**
     * Increase major version.
     */
    public void increaseMajorVersion() {
        try {
            updateInternalHistory();
            setMajorVersion(getMajorVersion() + 1);
            setMidVersion(0);
            setMinorVersion(0);
            updateInternalHistory();
        }
        catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    /**
     * Increase major version.
     */
    public void increaseMidVersion() {
        try {
            updateInternalHistory();
            setMidVersion(getMidVersion() + 1);
            setMinorVersion(0);
            updateInternalHistory();
        }
        catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    /**
     * Increase minor is done by default when updating a record.
     *
     * @param target Target of the update.
     * @param source Source of the update
     */
    public void update(Versionable target, Versionable source) {
        target.setDirty(source.getDirty());
        target.setMajorVersion(source.getMajorVersion());
        target.setMidVersion(source.getMidVersion());
        target.setMinorVersion(source.getMinorVersion());
        target.setModifierId(source.getModifierId());
        target.setReason(source.getReason());
        target.setModificationTime(source.getModificationTime());
        target.setHistoryList(source.getHistoryList());
        try {
            target.updateHistory();
        }
        catch (Exception ex) {
            LOG.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
        }
    }

    @Override
    public String toString() {
        return "Version: " + getMajorVersion() + "." + getMidVersion() + "."
                + getMinorVersion();
    }

    public enum CHANGE_LEVEL {
        MINOR,
        MODERATE,
        MAJOR
    }

    /**
     * Get history for this entity.
     *
     * @return history
     */
    public abstract List<History> getHistoryList();

    /**
     * Set history for this entity
     *
     * @param historyList History list to set.
     */
    public abstract void setHistoryList(List<History> historyList);

    @Override
    public int compareTo(Versionable o) {
        if (!Objects.equals(getMajorVersion(),
                o.getMajorVersion())) {
            return getMajorVersion() - o.getMajorVersion();
        }//Same major version
        else if (!Objects.equals(getMidVersion(),
                o.getMidVersion())) {
            return getMidVersion() - o.getMidVersion();
        } //Same mid version
        else if (!Objects.equals(getMinorVersion(),
                o.getMinorVersion())) {
            return getMinorVersion() - o.getMinorVersion();
        }
        //Everything the same
        return 0;
    }

    /**
     * Add history to this entity.
     *
     * @param history History to add.
     */
    public void addHistory(History history) {
        if (getHistoryList() == null) {
            setHistoryList(new ArrayList<>());
        }
        getHistoryList().add(history);
    }

    public static boolean fieldMatchHistory(HistoryField hf, Object value) {
        return !(value == null && !hf.getFieldValue().equals("null"))
                || (!(value instanceof byte[]) && value != null
                && !value.toString().equals(hf.getFieldValue()))
                || ((value instanceof byte[])
                && !new String((byte[]) value,
                        StandardCharsets.UTF_8)
                        .equals(hf.getFieldValue()));
    }

    public static synchronized boolean auditable(Versionable v) {
        History current;
        boolean result = false;
        if (v.getHistoryList() != null && !v.getHistoryList().isEmpty()) {
            current = v.getHistoryList().get(v.getHistoryList().size() - 1);
            for (HistoryField hf : current.getHistoryFieldList()) {
                try {
                    //Compare audit field vs. the record in history.
                    Object o = FieldUtils.readField(FieldUtils.getField(v.getClass(),
                            hf.getFieldName(), true), v);
                    if ((o == null && !hf.getFieldValue().equals("null"))
                            || (!(o instanceof byte[]) && o != null
                            && !o.toString().equals(hf.getFieldValue()))
                            || ((o instanceof byte[])
                            && !new String((byte[]) o,
                                    StandardCharsets.UTF_8)
                                    .equals(hf.getFieldValue()))) {
                        result = true;
                        break;
                    }
                }
                catch (SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                    LOG.log(Level.SEVERE, null, ex);
                }
            }
            //As last check the version fields for changes (i.e. baselineing, etc.)
            if (!result) {
                result = current.getMajorVersion() < v.getMajorVersion()
                        || current.getMidVersion() < v.getMidVersion()
                        || current.getMinorVersion() < v.getMinorVersion();
            }
            return result;
        }
        //No history so it is auditable if it has marked fields for audit.
        return !FieldUtils.getFieldsListWithAnnotation(v.getClass(),
                Auditable.class).isEmpty();
    }

    public void updateHistory() throws Exception {
        updateHistory(this);
    }

    protected void updateHistory(Versionable v) throws Exception {
        //Only if an auditable field has been modified
        if (auditable(v)) {
            //Add history of creation
            HistoryServer hs = new HistoryServer();
            VmUserJpaController c
                    = new VmUserJpaController(DataBaseManager.getEntityManagerFactory());
            if (v.getModifierId() <= 0) {
                try {
                    //By default blame system
                    hs.setModifierId(c.findVmUser(1));
                }
                catch (Exception ex) {
                    LOG.log(Level.SEVERE, null, ex);
                }
            } else {
                hs.setModifierId(c.findVmUser(v.getModifierId()));
            }

            if (v.getHistoryList() != null && !v.getHistoryList().isEmpty()) {
                if (v.getReason() == null
                        || v.getReason().equals("audit.general.creation")) {
                    v.setReason("audit.general.modified");
                }
                History last = v.getHistoryList().get(v.getHistoryList().size() - 1);
                if ((v.getMajorVersion() == 0 && v.getMidVersion() == 0) // It has default values
                        || last.getMajorVersion() == v.getMajorVersion() // Or it has a higher mid/major version assigned.
                        && last.getMidVersion() == v.getMidVersion()) {
                    //Make it one more than latest
                    hs.setMajorVersion(v.getMajorVersion());
                    hs.setMidVersion(v.getMidVersion());
                    hs.setMinorVersion(last.getMinorVersion() + 1);
                } else {
                    //Copy values from object as it was forced changed.
                    hs.setMajorVersion(v.getMajorVersion());
                    hs.setMidVersion(v.getMidVersion());
                    hs.setMinorVersion(v.getMinorVersion());
                }
            } else {
                if (v.getReason() == null) {
                    v.setReason("audit.general.creation");
                }
            }
            hs.setReason(v.getReason());
            hs.setModificationTime(v.getModificationTime() == null
                    ? new Date() : v.getModificationTime());
            hs.write2DB();
            if (v instanceof VmUser) {
                VmUser temp = (VmUser) v;
                if (Objects.equals(temp.getId(), hs.getModifierId().getId())) {
                    if (temp.getHistoryModificationList() == null) {
                        temp.setHistoryModificationList(new ArrayList<>());
                    }
                    temp.getHistoryModificationList().add(hs.getEntity());
                }
            } else {
                if (hs.getModifierId() != null) {
                    VmUser temp = c.findVmUser(hs.getModifierId().getId());
                    if (temp.getHistoryModificationList() == null) {
                        temp.setHistoryModificationList(new ArrayList<>());
                    }
                    temp.getHistoryModificationList().add(hs.getEntity());
                    c.edit(temp);
                }
            }
            //Check the fields to be placed in history
            updateFields(hs, v);
        }
        if (v.getHistoryList() != null && v.getHistoryList().size() > 0) {
            History current = v.getHistoryList().get(v.getHistoryList().size() - 1);
            //Update the version the object holds
            v.setMajorVersion(current.getMajorVersion());
            v.setMidVersion(current.getMidVersion());
            v.setMinorVersion(current.getMinorVersion());
        }
    }

    private synchronized void updateFields(HistoryServer hs, Versionable v)
            throws IllegalArgumentException, IllegalAccessException, Exception {
        for (Field field : FieldUtils.getFieldsListWithAnnotation(v.getClass(),
                Auditable.class)) {
            Class type = field.getType();
            String name = field.getName();
            FieldType ft = FieldTypeServer.findType(type.getSimpleName());
            if (ft == null) {
                FieldTypeServer fts = new FieldTypeServer();
                fts.setTypeName(type.getSimpleName());
                fts.write2DB();
                ft = fts.getEntity();
            }
            HistoryFieldServer hf
                    = new HistoryFieldServer(ft.getId(), hs.getId());
            hf.setFieldName(name);
            hf.setFieldType(ft);
            hf.setHistory(hs.getEntity());
            field.setAccessible(true);
            Object value = field.get(v);
            if (value instanceof byte[]) {
                byte[] bytes = (byte[]) value;
                value = new String(bytes, StandardCharsets.UTF_8);
            }
            hf.setFieldValue(value == null ? "null" : value.toString());
            hf.write2DB();
            hs.getHistoryFieldList().add(hf.getEntity());
        }
        hs.write2DB();
        v.addHistory(hs.getEntity());
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.tool;

import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import com.validation.manager.core.db.ExecutionStep;
import com.validation.manager.core.db.FailureModeHasCauseHasRiskCategory;
import com.validation.manager.core.db.Issue;
import com.validation.manager.core.db.Project;
import com.validation.manager.core.db.Requirement;
import com.validation.manager.core.db.RequirementSpec;
import com.validation.manager.core.db.RequirementSpecNode;
import com.validation.manager.core.db.RiskCategory;
import com.validation.manager.core.db.TestCase;
import com.validation.manager.core.db.TestCaseExecution;
import com.validation.manager.core.db.TestCasePK;
import com.validation.manager.core.server.core.ProjectServer;
import com.validation.manager.core.server.core.TestCaseExecutionServer;
import com.validation.manager.core.server.core.TestCaseServer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.swing.ImageIcon;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.tools.TextToPDF;
import org.openide.util.Exceptions;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
public class Tool {

    private static final Logger LOG
            = Logger.getLogger(Tool.class.getSimpleName());

    public static ImageIcon createImageIcon(String path, String description) {
        return createImageIcon(path, description, null);
    }

    public static ImageIcon createImageIcon(String path, String description, Class relativeTo) {
        URL imgURL = relativeTo == null ? Tool.class.getResource(path)
                : relativeTo.getResource(path);
        return imgURL == null ? null : new ImageIcon(imgURL, description);
    }

    public static void removeDuplicates(List list) {
        Set set = new HashSet();
        List newList = new ArrayList();
        for (Iterator iter = list.iterator(); iter.hasNext();) {
            Object element = iter.next();
            if (set.add(element)) {
                newList.add(element);
            }
        }
        list.clear();
        list.addAll(newList);
    }

    public static List<Requirement> extractRequirements(Project p) {
        ProjectServer ps;
        if (p instanceof ProjectServer) {
            ps = (ProjectServer) p;
        } else {
            ps = new ProjectServer(p);
        }
        List<Requirement> result = new ArrayList<>();
        ps.getRequirementSpecList().forEach(rs -> {
            result.addAll(extractRequirements(rs));
        });
        ps.getProjectList().forEach(sub -> {
            result.addAll(extractRequirements(sub));
        });
        return result;
    }

    public static List<Requirement> extractRequirements(RequirementSpecNode rsn) {
        ArrayList<Requirement> result = new ArrayList<>();
        rsn.getRequirementSpecNodeList().forEach(rsn2 -> {
            result.addAll(extractRequirements(rsn2));
        });
        result.addAll(rsn.getRequirementList());
        return result;
    }

    public static List<Requirement> extractRequirements(RequirementSpec rs) {
        ArrayList<Requirement> result = new ArrayList<>();
        rs.getRequirementSpecNodeList().forEach(rsn -> {
            result.addAll(extractRequirements(rsn));
        });
        return result;
    }

    public static TCEExtraction extractTCE(Object key) {
        TestCaseExecutionServer tce = null;
        TestCaseServer tcs = null;
        if (key instanceof String) {
            String item = (String) key;
            StringTokenizer st = new StringTokenizer(item, "-");
            st.nextToken();//Ignore the tce part
            String tceIdS = st.nextToken();
            try {
                int tceId = Integer.parseInt(tceIdS);
                LOG.log(Level.FINE, "{0}", tceId);
                tce = new TestCaseExecutionServer(tceId);
            }
            catch (NumberFormatException nfe) {
                LOG.log(Level.WARNING, "Unable to find TCE: " + tceIdS, nfe);
            }
            try {
                int tcId = Integer.parseInt(st.nextToken());
                int tcTypeId = Integer.parseInt(st.nextToken());
                LOG.log(Level.FINE, "{0}", tcId);
                tcs = new TestCaseServer(new TestCasePK(tcId, tcTypeId));
            }
            catch (NumberFormatException nfe) {
                LOG.log(Level.WARNING, "Unable to find TCE: " + tceIdS, nfe);
            }
        } else if (key instanceof TestCaseExecution) {
            //It is a TestCaseExecution
            tce = new TestCaseExecutionServer((TestCaseExecution) key);
        } else {
            LOG.log(Level.SEVERE, "Unexpected key: {0}", key);
            tce = null;
        }
        return new TCEExtraction(tce, tcs);
    }

    public static File convertToPDF(File f, String filename)
            throws FileNotFoundException,
            IOException {
        TextToPDF ttp = new TextToPDF();
        File pdf;
        try (PDDocument pdfd = ttp.createPDFFromText(new FileReader(f))) {
            pdf = new File(filename);
            if (pdf.getParentFile() != null) {
                pdf.getParentFile().mkdirs();
            }
            pdfd.save(pdf);
        }
        pdf.deleteOnExit();
        return pdf;
    }

    public static File convertToPDF(String content, String filename)
            throws FileNotFoundException,
            IOException {
        Path path = Files.createTempFile("temp-file", ".txt");
        File file = path.toFile();
        Files.write(path, content.getBytes(StandardCharsets.UTF_8));
        return convertToPDF(file, filename);
    }

    public static String getMimeType(File f) throws IOException {
        return getMimeType(f.getName());
    }

    public static String getMimeType(String fileName) throws IOException {
        ContentInfoUtil util = new ContentInfoUtil();
        ContentInfo info = util.findMatch(fileName);
        return info.getMimeType();
    }

    public static File createZipFile(List<File> files, String zipName)
            throws FileNotFoundException, IOException {
        if (!zipName.endsWith(".zip")) {
            zipName += ".zip";
        }
        File f = new File(zipName);
        if (f.getParentFile() != null) {
            f.getParentFile().mkdirs();
        }
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
            files.forEach(file -> {
                try {
                    ZipEntry ze = new ZipEntry(file.getName());
                    out.putNextEntry(ze);
                    byte[] data = FileUtils.readFileToByteArray(file);
                    out.write(data, 0, data.length);
                    out.closeEntry();
                }
                catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            });
        }
        return f;
    }

    /**
     * Builder of unique id's for items.
     *
     * @param item Item to get the id from
     * @param postfix postfix to add to the key
     * @param usePrefix Use the prefix?
     * @return key for the object
     */
    public static Object buildId(Object item, Object postfix, boolean usePrefix) {
        Object pf;
        Object key = null;
        String prefix;
        if (postfix == null) {
            pf = "";
        } else {
            pf = "-" + postfix;
        }
        if (item instanceof TestCase) {
            TestCase tc = (TestCase) item;
            prefix = "tc";
            key = (usePrefix ? prefix + "-" : "") + tc.getTestCasePK().getId()
                    + "-" + tc.getTestCasePK().getTestCaseTypeId()
                    + pf;
        } else if (item instanceof Requirement) {
            Requirement r = (Requirement) item;
            key = r.getUniqueId() + pf;
        } else if (item instanceof ExecutionStep) {
            ExecutionStep es = (ExecutionStep) item;
            prefix = "es";
            key = (usePrefix ? prefix + "-" : "")
                    + es.getExecutionStepPK().getStepId() + "-"
                    + es.getExecutionStepPK().getStepTestCaseId() + "-"
                    + es.getExecutionStepPK().getTestCaseExecutionId() + pf;
        } else if (item instanceof Issue) {
            Issue issue = (Issue) item;
            prefix = "issue";
            key = (usePrefix ? prefix + "-" : "") + issue.getIssuePK().getId() + pf;
        } else if (item instanceof TestCaseExecution) {
            TestCaseExecution tce = (TestCaseExecution) item;
            prefix = "tce";
            key = (usePrefix ? prefix + "-" : "") + tce.getId() + pf;
        }
        return key;
    }

    /**
     * Builder of unique id's for items.
     *
     * @param item Item to get the id from
     * @return key for the object
     */
    public static Object buildId(Object item) {
        return buildId(item, null, true);
    }

    /**
     * Builder of unique id's for items.
     *
     * @param item Item to get the id from
     * @param postfix postfix to add to the key
     * @return key for the object
     */
    public static Object buildId(Object item, Object postfix) {
        return buildId(item, postfix, true);
    }

    public static Double evaluateEquation(FailureModeHasCauseHasRiskCategory fmhchrc) {
        RiskCategory cat = fmhchrc.getRiskCategory();
        if (cat.getCategoryEquation() != null
                && !cat.getCategoryEquation().trim().isEmpty()) {
            //Calculate based on equation
            //Format: {rc-id} where id -s the category id
            //i.e.: {rc-1} * {rc-2}
            Map<Integer, Double> map = new HashMap<>();
            fmhchrc.getFailureModeHasCause()
                    .getFailureModeHasCauseHasRiskCategoryList()
                    .forEach(temp -> {
                        //Put result or null if calculated in map.
                        map.put(temp.getRiskCategory().getId(),
                                temp.getRiskCategory().getCategoryEquation() == null
                                || temp.getRiskCategory()
                                        .getCategoryEquation().trim()
                                        .isEmpty()
                                        ? temp.getCategoryValue() : null);
                    });
            //Make the calculation. All values are in map
            String stringPattern = "rc-[0-9]+";
            String equation = fmhchrc.getRiskCategory()
                    .getCategoryEquation().trim();
            String finalEq = equation;
            Pattern pattern = Pattern.compile(stringPattern);
            Matcher matcher = pattern.matcher(equation);
            Map<String, Double> variables = new HashMap<>();
            int variableCounter = 0;
            LOG.log(Level.FINE, "Calculating equation: {0}", equation);
            finalEq = finalEq.replaceAll("\\{", "").replaceAll("\\}", "");
            while (matcher.find()) {
                //Replace with a variable
                String variable = getStringSequence(variableCounter++)
                        .toLowerCase();
                String value = matcher.group(0);
                finalEq = finalEq.replaceAll(value, variable);
                variables.put(variable,
                        map.get(Integer.parseInt(value
                                .substring(value.indexOf('-') + 1,
                                        value.length()))));
            }
            LOG.log(Level.FINE, "Final equation: {0}\n{1}",
                    new Object[]{finalEq, variables});
            Expression e = new ExpressionBuilder(finalEq)
                    .variables(variables.keySet())
                    .build()
                    .setVariables(variables);
            return e.evaluate();
        }
        return new Double(0);
    }

    /**
     * See: https://stackoverflow.com/a/32532049/198108
     *
     * @param i Integer to convert
     * @return Sequential letters.
     */
    private static String getStringSequence(int i) {
        return i < 0 ? "" : getStringSequence((i / 26) - 1) + (char) (65 + i % 26);
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.server;

import com.validation.manager.core.VMException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.logging.Logger.getLogger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.JNDIConnector;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.server.ServerSession;

/**
 * See http://wiki.eclipse.org/Customizing_the_EclipseLink_Application_(ELUG)
 * Use for clients that would like to use a JTA SE pu instead of a
 * RESOURCE_LOCAL SE pu.
 */
public class JPAEclipseLinkSessionCustomizer implements SessionCustomizer {

    public static final String JNDI_DATASOURCE_NAME = "java:comp/env/jdbc/VMDB";
    private static final Logger LOG
            = getLogger(JPAEclipseLinkSessionCustomizer.class.getSimpleName());

    /**
     * Get a dataSource connection and set it on the session with
     * lookupType=STRING_LOOKUP
     *
     * @param session Session
     * @throws java.lang.Exception If an error occurs.
     */
    @Override
    public void customize(Session session) throws Exception {
        JNDIConnector connector;
        // Initialize session customizer
        DataSource dataSource;
        try {
            Context context = new InitialContext();
            if (null == context) {
                throw new VMException("Context is null");
            }
            connector = (JNDIConnector) session.getLogin().getConnector(); // possible CCE
            // Lookup this new dataSource
            dataSource = (DataSource) context.lookup(JNDI_DATASOURCE_NAME);
            connector.setDataSource(dataSource);
            // Change from COMPOSITE_NAME_LOOKUP to STRING_LOOKUP
            // Note: if both jta and non-jta elements exist this will only change the first one - and may still result in the COMPOSITE_NAME_LOOKUP being set
            // Make sure only jta-data-source is in persistence.xml with no non-jta-data-source property set
            connector.setLookupType(JNDIConnector.STRING_LOOKUP);

            // if you are specifying both JTA and non-JTA in your persistence.xml then set both connectors to be safe
            JNDIConnector writeConnector
                    = (JNDIConnector) session.getLogin().getConnector();
            writeConnector.setLookupType(JNDIConnector.STRING_LOOKUP);
            JNDIConnector readConnector
                    = (JNDIConnector) ((DatabaseLogin) ((ServerSession) session)
                            .getReadConnectionPool().getLogin()).getConnector();
            readConnector.setLookupType(JNDIConnector.STRING_LOOKUP);

            // Set the new connection on the session
            session.getLogin().setConnector(connector);
        }
        catch (Exception e) {
            LOG.log(Level.SEVERE, JNDI_DATASOURCE_NAME, e);
        }
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.server.core;

import static com.validation.manager.core.DataBaseManager.getEntityManagerFactory;
import com.validation.manager.core.EntityServer;
import com.validation.manager.core.db.Requirement;
import com.validation.manager.core.db.RequirementSpec;
import com.validation.manager.core.db.controller.ProjectJpaController;
import com.validation.manager.core.db.controller.RequirementSpecJpaController;
import com.validation.manager.core.db.controller.RequirementSpecNodeJpaController;
import com.validation.manager.core.db.controller.SpecLevelJpaController;
import com.validation.manager.core.db.controller.exceptions.IllegalOrphanException;
import com.validation.manager.core.db.controller.exceptions.NonexistentEntityException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
public final class RequirementSpecServer extends RequirementSpec
        implements EntityServer<RequirementSpec> {

    public RequirementSpecServer(String name, String description,
            int projectId, int specLevelId) {
        super(projectId, specLevelId);
        setProject(new ProjectJpaController(getEntityManagerFactory())
                .findProject(projectId));
        setSpecLevel(new SpecLevelJpaController(getEntityManagerFactory())
                .findSpecLevel(specLevelId));
        setDescription(description);
        setName(name);
        setModificationDate(new Date());
        setRequirementSpecNodeList(new ArrayList<>());
        setBaselineList(new ArrayList<>());
    }

    public RequirementSpecServer(RequirementSpec rs) {
        super(rs.getRequirementSpecPK());
        update();
    }

    /**
     * Add a node to this spec.
     *
     * This is equivalent to a section in a document.
     *
     * Although database might allow a requirement being on different nodes,
     * this constraint is imposed via software.
     *
     * @param name name of new node
     * @param description description of node
     * @param scope scope of node
     * @return Created node.
     * @throws Exception if errors creating the node occur
     */
    public RequirementSpecNodeServer addSpecNode(String name,
            String description, String scope) throws Exception {
        RequirementSpecNodeServer sns = new RequirementSpecNodeServer(
                new RequirementSpecJpaController(
                        getEntityManagerFactory())
                        .findRequirementSpec(getRequirementSpecPK()),
                name, description, scope);
        sns.write2DB();
        getRequirementSpecNodeList().add(
                new RequirementSpecNodeJpaController(
                        getEntityManagerFactory())
                        .findRequirementSpecNode(sns.getRequirementSpecNodePK()));
        write2DB();
        return sns;
    }

    @Override
    public int write2DB() throws Exception {
        if (getRequirementSpecNodeList() == null) {
            setRequirementSpecNodeList(new ArrayList<>());
        }
        if (getRequirementSpecPK() != null
                && getRequirementSpecPK().getId() > 0) {
            RequirementSpec rs = new RequirementSpecJpaController(
                    getEntityManagerFactory())
                    .findRequirementSpec(getRequirementSpecPK());
            update(rs, this);
            new RequirementSpecJpaController(
                    getEntityManagerFactory()).edit(rs);
        } else {
            RequirementSpec rs = new RequirementSpec();
            update(rs, this);
            new RequirementSpecJpaController(
                    getEntityManagerFactory()).create(rs);
            setRequirementSpecPK(rs.getRequirementSpecPK());
        }
        return getRequirementSpecPK().getId();
    }

    public static void deleteRequirementSpec(RequirementSpec rs)
            throws IllegalOrphanException, NonexistentEntityException {
        new RequirementSpecJpaController(
                getEntityManagerFactory())
                .destroy(rs.getRequirementSpecPK());
    }

    @Override
    public RequirementSpec getEntity() {
        return new RequirementSpecJpaController(
                getEntityManagerFactory())
                .findRequirementSpec(getRequirementSpecPK());
    }

    @Override
    public void update(RequirementSpec target, RequirementSpec source) {
        target.setProject(source.getProject());
        target.setSpecLevel(source.getSpecLevel());
        target.setDescription(source.getDescription());
        target.setName(source.getName());
        target.setModificationDate(source.getModificationDate());
        target.setRequirementSpecNodeList(source.getRequirementSpecNodeList());
        target.setRequirementSpecPK(source.getRequirementSpecPK());
        target.setBaselineList(source.getBaselineList());
    }

    public static List<Requirement> getRequirements(RequirementSpec spec) {
        List<Requirement> requirements = new ArrayList<>();
        RequirementSpecServer rs = new RequirementSpecServer(spec);
        rs.getRequirementSpecNodeList().forEach((rsn) -> {
            requirements.addAll(RequirementSpecNodeServer.getRequirements(rsn));
        });
        return requirements;
    }

    @Override
    public void update() {
        update(this, getEntity());
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 net.sourceforge.javydreamercsw.validation.manager.web.filter;

import java.io.IOException;
import javax.servlet.*;

/**
 *
 * @author Leo-Fan.aq
 */
public class SetCharacterEncodingFilter implements Filter {
    // ----------------------------------------------------- Instance Variables

    /**
     * The default character encoding to set for requests that pass through this
     * filter.
     */
    protected String encoding = null;
    /**
     * The filter configuration object we are associated with. If this value is
     * null, this filter instance is not currently configured.
     */
    protected FilterConfig filterConfig = null;
    /**
     * Should a character encoding specified by the client be ignored?
     */
    protected boolean ignore = true;

    // --------------------------------------------------------- Public Methods
    /**
     * Take this filter out of service.
     */
    @Override
    public void destroy() {

        this.encoding = null;
        this.filterConfig = null;

    }

    /**
     * Select and set (if specified) the character encoding to be used to
     * interpret request parameters for this request.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     * @param chain The filter chain we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {

        // Conditionally select and set the character encoding to be used
        if (ignore || (request.getCharacterEncoding() == null)) {
            String tempEncoding = selectEncoding(request);
            if (tempEncoding != null) {
                request.setCharacterEncoding(tempEncoding);
            }
        }

        // Pass control on to the next filter
        chain.doFilter(request, response);
    }

    /**
     * Place this filter into service.
     *
     * @param filterConfig The filter configuration object
     * @throws javax.servlet.ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        this.ignore = value == null ? false : value.equalsIgnoreCase("true")
                || value.equalsIgnoreCase("yes");
    }

    // ------------------------------------------------------ Protected Methods
    /**
     * Select an appropriate character encoding to be used, based on the
     * characteristics of the current request and/or filter initialization
     * parameters. If no character encoding should be set, return
     * null.
     *

     * The default implementation unconditionally returns the value configured
     * by the encoding initialization parameter for this
     * filter.
     *
     * @param request The servlet request we are processing
     * @return encoding.
     */
    protected String selectEncoding(ServletRequest request) {
        return (this.encoding);
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.server.core;

import static com.validation.manager.core.DataBaseManager.getEntityManagerFactory;
import static com.validation.manager.core.DataBaseManager.namedQuery;
import com.validation.manager.core.EntityServer;
import com.validation.manager.core.VMException;
import com.validation.manager.core.db.VmId;
import com.validation.manager.core.db.controller.VmIdJpaController;
import com.validation.manager.core.db.controller.exceptions.NonexistentEntityException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Javier A. Ortiz Bultronjavier.ortiz.78@gmail.com
 */
public final class VMIdServer extends VmId implements EntityServer<VmId> {

    private static final long serialVersionUID = 1L;
    private static final Logger LOG
            = Logger.getLogger(VMIdServer.class.getSimpleName());

    public VMIdServer(Integer id) throws VMException {
        super.setId(id);
        update();
    }

    public VMIdServer(String tablename, int lastId) {
        super(tablename, lastId);
    }

    //write to db
    @Override
    public int write2DB() throws VMException {
        try {
            VmIdJpaController controller = new VmIdJpaController(
                    getEntityManagerFactory());
            VmId vmId;
            if (getId() == null) {
                vmId = new VmId();
                update(vmId, this);
                controller.create(vmId);
                setId(vmId.getId());
            } else {
                vmId = getEntity();
                update(vmId, this);
                controller.edit(vmId);
            }
            update();
            return getId();
        }
        catch (Exception ex) {
            LOG.log(Level.SEVERE, null, ex);
            throw new VMException(ex);
        }
    }

    public static int deleteFromDB(VmId id) throws VMException {
        VmIdJpaController controller = new VmIdJpaController(
                getEntityManagerFactory());
        if (id != null) {
            try {
                controller.destroy(id.getId());
            }
            catch (NonexistentEntityException ex) {
                throw new VMException(ex);
            }
        }
        return 0;
    }

    public static VMIdServer getVMId(String table) throws VMException {
        PARAMETERS.clear();
        PARAMETERS.put("tableName", table);
        List<Object> result = namedQuery("VmId.findByTableName", PARAMETERS);
        if (!result.isEmpty()) {
            return new VMIdServer(((VmId) result.get(0)).getId());
        } else {
            LOG.log(Level.WARNING, "Unable to find VM id for: {0}", table);
            return null;
        }
    }

    public static int getNextId(String table) throws VMException {
        VMIdServer vmId = getVMId(table);
        vmId.setLastId(vmId.getLastId() + 1);
        vmId.write2DB();
        return vmId.getLastId();
    }

    public static List<VMIdServer> getIds() throws VMException {
        ArrayList<VMIdServer> ids = new ArrayList<>();
        List<Object> result = namedQuery("VMId.findAll");
        if (!result.isEmpty()) {
            for (Object o : result) {
                ids.add(new VMIdServer(((VmId) o).getId()));
            }
        } else {
            throw new VMException("No ids found!");
        }
        return ids;
    }

    @Override
    public VmId getEntity() {
        return new VmIdJpaController(
                getEntityManagerFactory()).findVmId(getId());
    }

    @Override
    public void update(VmId target, VmId source) {
        target.setId(source.getId());
        target.setLastId(source.getLastId());
        target.setTableName(source.getTableName());
    }

    @Override
    public void update() {
        update(this, getEntity());
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.server.core;

import com.validation.manager.core.DataBaseManager;
import com.validation.manager.core.EntityServer;
import com.validation.manager.core.db.IssueType;
import com.validation.manager.core.db.controller.IssueTypeJpaController;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
public class IssueTypeServer extends IssueType
        implements EntityServer<IssueType> {

    public IssueTypeServer(int id) {
        setId(id);
        update();
    }

    public IssueTypeServer(String typeName) {
        super(typeName);
    }

    @Override
    public int write2DB() throws Exception {
        if (getId() == null) {
            IssueType i = new IssueType();
            update(i, this);
            new IssueTypeJpaController(DataBaseManager
                    .getEntityManagerFactory()).create(i);
            update(this, i);
        } else {
            IssueType i = getEntity();
            update(i, this);
            new IssueTypeJpaController(DataBaseManager
                    .getEntityManagerFactory()).edit(i);
            update(this, i);
        }
        return getId();
    }

    @Override
    public IssueType getEntity() {
        return new IssueTypeJpaController(DataBaseManager
                .getEntityManagerFactory()).findIssueType(getId());
    }

    @Override
    public void update(IssueType target, IssueType source) {
        target.setDescription(source.getDescription());
        target.setIssueList(source.getIssueList());
        target.setTypeName(source.getTypeName());
    }

    @Override
    public void update() {
        update(this, getEntity());
    }

    /**
     * Get an Issue Type by name.
     *
     * @param typename name to search for
     * @return Issue Type for the specified name or null if not found.
     */
    public static IssueType getType(String typename) {
        IssueType result = null;
        for (IssueType type : new IssueTypeJpaController(DataBaseManager
                .getEntityManagerFactory()).findIssueTypeEntities()) {
            if (type.getTypeName().equals(typename)) {
                result = type;
                break;
            }
        }
        return result;
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.server.core;

import static com.validation.manager.core.DataBaseManager.getEntityManagerFactory;
import static com.validation.manager.core.DataBaseManager.namedQuery;
import com.validation.manager.core.EntityServer;
import com.validation.manager.core.VMException;
import com.validation.manager.core.db.VmSetting;
import com.validation.manager.core.db.controller.VmSettingJpaController;
import com.validation.manager.core.db.controller.exceptions.NonexistentEntityException;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
public final class VMSettingServer extends VmSetting
        implements EntityServer<VmSetting>, VersionableServer<VmSetting> {

    private static List<Object> result;

    public VMSettingServer(String setting) throws VMException {
        VmSetting s = getSetting(setting);
        if (s != null) {
            super.setId(s.getId());
            update();
        } else {
            throw new VMException("Setting: " + setting
                    + " doesn't exist!");
        }
    }

    public VMSettingServer(String setting, boolean boolVal, int intVal,
            long longVal, String stringVal) {
        super(setting);
        setBoolVal(boolVal);
        setIntVal(intVal);
        setLongVal("" + longVal);
        setSetting(setting);
        setStringVal(stringVal);
    }

    /**
     * Get setting from database
     *
     * @param s Setting name to retrieve
     * @return Setting with the specified name.
     */
    @SuppressWarnings("unchecked")
    public static VmSetting getSetting(String s) {
        PARAMETERS.clear();
        PARAMETERS.put("setting", s);
        result = namedQuery("VmSetting.findBySetting",
                PARAMETERS);
        if (result.isEmpty()) {
            return null;
        } else {
            return (VmSetting) result.get(0);
        }
    }

    @SuppressWarnings("unchecked")
    public static ArrayList<VmSetting> getSettings() {
        ArrayList<VmSetting> settings = new ArrayList<>();
        result = namedQuery("VmSetting.findAll");
        result.forEach((o) -> {
            settings.add((VmSetting) o);
        });
        return settings;
    }

    @Override
    public int write2DB() throws NonexistentEntityException, Exception {
        if (getId() != null) {
            VmSetting s = new VmSettingJpaController(
                    getEntityManagerFactory())
                    .findVmSetting(getId());
            update(s, this);
            new VmSettingJpaController(
                    getEntityManagerFactory()).edit(s);
        } else {
            VmSetting s = new VmSetting();
            update(s, this);
            new VmSettingJpaController(
                    getEntityManagerFactory()).create(s);
            setId(s.getId());
        }
        return getId();
    }

    @Override
    public VmSetting getEntity() {
        return new VmSettingJpaController(
                getEntityManagerFactory())
                .findVmSetting(getId());
    }

    @Override
    public void update(VmSetting target, VmSetting source) {
        target.setBoolVal(source.getBoolVal());
        target.setIntVal(source.getIntVal());
        target.setLongVal(source.getLongVal());
        target.setSetting(source.getSetting());
        target.setStringVal(source.getStringVal());
        target.setId(source.getId());
        target.setHistoryList(source.getHistoryList());
        target.setProjectId(source.getProjectId());
        super.update(target, source);
    }

    @Override
    public void update() {
        update(this, getEntity());
    }
}


/*
 * Copyright 2017 Javier A. Ortiz Bultron javier.ortiz.78@gmail.com.
 *
 * 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 com.validation.manager.core.server.core;

import com.validation.manager.core.DataBaseManager;
import com.validation.manager.core.EntityServer;
import com.validation.manager.core.db.DataEntry;
import com.validation.manager.core.db.DataEntryProperty;
import com.validation.manager.core.db.DataEntryType;
import com.validation.manager.core.db.controller.DataEntryJpaController;
import java.util.ArrayList;
import java.util.List;
import org.openide.util.Exceptions;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
public final class DataEntryServer extends DataEntry implements EntityServer<DataEntry> {

    public DataEntryServer(DataEntry de) {
        update(DataEntryServer.this, de);
    }

    @Override
    public int write2DB() throws Exception {
        DataEntryJpaController c = new DataEntryJpaController(DataBaseManager
                .getEntityManagerFactory());
        if (getDataEntryPK() == null) {
            DataEntry de = new DataEntry();
            update(de, this);
            List<DataEntryProperty> dest = new ArrayList<>();
            if (getDataEntryPropertyList() != null) {
                dest = new ArrayList<>(getDataEntryPropertyList());
                de.setDataEntryPropertyList(new ArrayList<>());
            }
            c.create(de);
            dest.forEach(dep -> {
                try {
                    DataEntryPropertyServer deps = new DataEntryPropertyServer(dep);
                    deps.setDataEntry(de);
                    deps.write2DB();
                    deps.update(dep, deps);
                }
                catch (Exception ex) {
                    Exceptions.printStackTrace(ex);
                }
            });
            setDataEntryPK(de.getDataEntryPK());
        } else {
            DataEntry de = getEntity();
            update(de, this);
            c.edit(de);
        }
        update();
        return getDataEntryPK().getId();
    }

    @Override
    public DataEntry getEntity() {
        return new DataEntryJpaController(DataBaseManager
                .getEntityManagerFactory()).findDataEntry(getDataEntryPK());
    }

    @Override
    public void update(DataEntry target, DataEntry source) {
        target.setDataEntryPK(source.getDataEntryPK());
        target.setDataEntryPropertyList(source.getDataEntryPropertyList());
        target.setDataEntryType(source.getDataEntryType());
        target.setEntryName(source.getEntryName());
        target.setStep(source.getStep());
    }

    @Override
    public void update() {
        update(this, getEntity());
    }

    /**
     * Create a default string field
     *
     * @param name Field name
     * @return DataEntry. The entry is not persisted into the database yet.
     */
    public static DataEntry getStringField(String name) {
        return getStringField(name, null, false);
    }

    /**
     * Create a default string field
     *
     * @param name Field name
     * @param expected Expected result.
     * @param matchCase True if answer must match the case of the expected
     * result. False otherwise.
     * @return DataEntry. The entry is not persisted into the database yet.
     */
    public static DataEntry getStringField(String name, String expected,
            boolean matchCase) {
        DataEntry de = new DataEntry();
        DataEntryType det = DataEntryTypeServer.getType("type.string.name");
        de.setEntryName(name);
        de.setDataEntryPropertyList(getDefaultProperties(det));
        de.setDataEntryType(det);
        if (expected != null) {
            getProperty(de, "property.expected.result")
                    .setPropertyValue(expected);
            getProperty(de, "property.match.case")
                    .setPropertyValue(matchCase ? "true" : "false");
        }
        return de;
    }

    /**
     * Create a boolean field
     *
     * @param name Field name
     * @return DataEntry. The entry is not persisted into the database yet.
     */
    public static DataEntry getBooleanField(String name) {
        DataEntry de = new DataEntry();
        de.setEntryName(name);
        DataEntryType det = DataEntryTypeServer.getType("type.boolean.name");
        de.setDataEntryPropertyList(getDefaultProperties(det));
        de.setDataEntryType(det);
        return de;
    }

    /**
     * Create a boolean field
     *
     * @param name Field name
     * @param expected Expected result
     * @return DataEntry. The entry is not persisted into the database yet.
     */
    public static DataEntry getBooleanField(String name, boolean expected) {
        DataEntry de = new DataEntry();
        de.setEntryName(name);
        DataEntryType det = DataEntryTypeServer.getType("type.boolean.name");
        de.setDataEntryPropertyList(getDefaultProperties(det));
        de.setDataEntryType(det);
        getProperty(de, "property.expected.result")
                .setPropertyValue(expected ? "true" : "false");
        return de;
    }

    /**
     * Create a attachment field
     *
     * @param name Field name
     * @return DataEntry. The entry is not persisted into the database yet.
     */
    public static DataEntry getAttachmentField(String name) {
        DataEntry de = new DataEntry();
        de.setEntryName(name);
        DataEntryType det = DataEntryTypeServer.getType("type.attachment.name");
        de.setDataEntryPropertyList(getDefaultProperties(det));
        de.setDataEntryType(det);
        return de;
    }

    /**
     * Create a numeric field.
     *
     * @param name Field name
     * @param min Minimum value. Set as null for no limit.
     * @param max Maximum value. Set as null for no limit.
     * @return DataEntry. The entry is not persisted into the database yet.
     */
    public static DataEntry getNumericField(String name, Float min, Float max) {
        DataEntry de = new DataEntry();
        de.setEntryName(name);
        DataEntryType det = DataEntryTypeServer.getType("type.numeric.name");
        de.setDataEntryPropertyList(getDefaultProperties(det));
        de.setDataEntryType(det);
        for (DataEntryProperty dep : de.getDataEntryPropertyList()) {
            if (dep.getPropertyName().equals("property.min") && min != null) {
                //Set minimum
                dep.setPropertyValue(min.toString());
            }
            if (dep.getPropertyName().equals("property.max") && max != null) {
                //Set minimum
                dep.setPropertyValue(max.toString());
            }
        }
        return de;
    }

    public static List<DataEntryProperty> getDefaultProperties(DataEntryType det) {
        List<DataEntryProperty> props = new ArrayList<>();
        //Required by default
        props.add(DataEntryPropertyServer
                .createProperty("property.required", true));
        switch (det.getId()) {
            case 2://Numeric: add value range
                props.add(DataEntryPropertyServer
                        .createProperty("property.min", null));
                props.add(DataEntryPropertyServer
                        .createProperty("property.max", null));
                break;
            case 1://Additional properties for text fields
                props.add(DataEntryPropertyServer
                        .createProperty("property.match.case", false));
            //Fall thru
            default:
                //Property for expected result.
                props.add(DataEntryPropertyServer
                        .createProperty("property.expected.result", null));
        }
        return props;
    }

    public static DataEntryProperty getProperty(DataEntry de, String name) {
        DataEntryProperty prop = null;
        for (DataEntryProperty p : de.getDataEntryPropertyList()) {
            if (p.getPropertyName().equals(name)) {
                prop = p;
                break;
            }
        }
        return prop;
    }
}