/*
 * Copyright 2017 ortizj.
 *
 * 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.workflow;

import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.pontus.vizcomponent.VizComponent;
import com.vaadin.pontus.vizcomponent.VizComponent.EdgeClickEvent;
import com.vaadin.pontus.vizcomponent.VizComponent.NodeClickEvent;
import com.vaadin.pontus.vizcomponent.model.Graph;
import com.vaadin.pontus.vizcomponent.model.Subgraph;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import static com.validation.manager.core.ContentProvider.TRANSLATOR;
import com.validation.manager.core.DataBaseManager;
import com.validation.manager.core.VMException;
import com.validation.manager.core.db.Workflow;
import com.validation.manager.core.db.WorkflowStep;
import com.validation.manager.core.db.controller.WorkflowJpaController;
import com.validation.manager.core.server.core.WorkflowServer;
import de.steinwedel.messagebox.ButtonOption;
import de.steinwedel.messagebox.MessageBox;
import java.util.AbstractMap;
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 net.sourceforge.javydreamercsw.validation.manager.web.ValidationManagerUI;
import net.sourceforge.javydreamercsw.validation.manager.web.component.VMWindow;
import org.vaadin.addon.borderlayout.BorderLayout;
import org.vaadin.addon.borderlayout.BorderLayout.Constraint;

/**
 *
 * @author Javier A. Ortiz Bultron javier.ortiz.78@gmail.com
 */
public final class WorkflowViewer extends VMWindow {

    private final VizComponent diagram = new VizComponent();
    private final List<Object> added = new ArrayList<>();
    private final List<Object> deleted = new ArrayList<>();
    private final Map<Integer, Graph.Node> nodes = new HashMap<>();
    //Map has source node and edge. Destination is part of the Edge object
    private final Map<String, AbstractMap.SimpleEntry<Graph.Node, Subgraph.Edge>> edges = new HashMap<>();
    private static final Logger LOG
            = Logger.getLogger(WorkflowViewer.class.getSimpleName());
    private Object selected = null;
    private final BorderLayout bl = new BorderLayout();
    private final ListSelect workflows
            = new ListSelect(TRANSLATOR.translate("general.workflow"));
    private int count = 0;
    private final String KEY = "key", ITEM_NAME = "itemName";

    public WorkflowViewer() {
        super(TRANSLATOR.translate("workflow.manager"));
        init();
    }

    public WorkflowViewer(String caption) {
        super(caption);
        init();
    }

    private void cleanGraph() {
        //Reset nodes to black
        nodes.values().forEach(node -> {
            diagram.addCss(node, "stroke", "black");
            diagram.addTextCss(node, "fill", "black");
        });
        //Reset edges to black
        edges.values().forEach(edge -> {
            diagram.addCss(edge.getValue(), "stroke", "black");
            diagram.addTextCss(edge.getValue(), "fill", "black");
        });
    }

    protected void init() {
        setSizeFull();
        setModal(false);
        diagram.addClickListener((NodeClickEvent e) -> {
            cleanGraph();
            diagram.addCss(e.getNode(), "stroke", "blue");
            diagram.addTextCss(e.getNode(), "fill", "blue");
            selected = e.getNode();
            updateControls();
        });
        diagram.addClickListener((EdgeClickEvent e) -> {
            cleanGraph();
            diagram.addCss(e.getEdge(), "stroke", "blue");
            diagram.addTextCss(e.getEdge(), "fill", "blue");
            selected = e.getEdge();
            updateControls();
        });
        diagram.setSizeFull();
        String width = "200px";
        bl.setMinimumWestWidth(width);
        bl.setMinimumEastWidth(width);
        bl.addComponent(getControls(), Constraint.EAST);
        bl.addComponent(getList(), Constraint.WEST);
        bl.addComponent(diagram, Constraint.CENTER);
        bl.setSizeFull();
        setContent(bl);
    }

    private Component getControls() {
        VerticalLayout controls = new VerticalLayout();
        Button addStep = new Button(TRANSLATOR.translate("general.add.step"));
        VerticalLayout vl = new VerticalLayout();
        TextField name = new TextField(TRANSLATOR.translate("general.name"));
        vl.addComponent(name);
        addStep.addClickListener(listener -> {
            MessageBox prompt = MessageBox.createQuestion()
                    .withCaption(TRANSLATOR.translate("general.add.step"))
                    .withMessage(vl)
                    .withYesButton(() -> {
                        if (name.getValue() != null
                                && !name.getValue().isEmpty()) {
                            Graph.Node node
                                    = new Graph.Node(TRANSLATOR.translate(name.getValue()));
                            nodes.put(--count, node);
                            node.setParam(KEY, "" + count);
                            node.setParam(ITEM_NAME,
                                    TRANSLATOR.translate(name.getValue()));
                            added.add(node);
                            refreshWorkflow();
                        }
                    },
                            ButtonOption.focus(),
                            ButtonOption
                                    .icon(VaadinIcons.CHECK))
                    .withNoButton(ButtonOption.icon(VaadinIcons.CLOSE));
            prompt.getWindow().setIcon(ValidationManagerUI.SMALL_APP_ICON);
            prompt.open();
        });
        addStep.setWidth(100, Unit.PERCENTAGE);
        addStep.setEnabled(workflows.getValue() != null);
        controls.addComponent(addStep);
        Button addTransition = new Button(TRANSLATOR.translate("general.add.transition"));
        VerticalLayout vl2 = new VerticalLayout();
        TextField transitionName = new TextField(TRANSLATOR.translate("general.name"));
        ListSelect nodeList = new ListSelect(TRANSLATOR.translate("general.step"));
        BeanItemContainer<Graph.Node> container
                = new BeanItemContainer<>(Graph.Node.class, nodes.values());
        nodeList.setContainerDataSource(container);
        nodeList.getItemIds().forEach(id -> {
            Graph.Node temp = ((Graph.Node) id);
            nodeList.setItemCaption(id, temp.getId());
        });
        nodeList.setNullSelectionAllowed(false);
        vl2.addComponent(transitionName);
        vl2.addComponent(nodeList);
        addTransition.addClickListener(listener -> {
            MessageBox prompt = MessageBox.createQuestion()
                    .withCaption(TRANSLATOR.translate("general.add.transition"))
                    .withMessage(vl2)
                    .withYesButton(() -> {
                        if (transitionName.getValue() != null
                                && !transitionName.getValue().isEmpty()
                                && selected instanceof Subgraph.Node) {
                            Subgraph.Edge edge
                                    = new Subgraph.Edge();
                            edge.setDest((Subgraph.Node) nodeList.getValue());
                            edges.put(transitionName.getValue(),
                                    new AbstractMap.SimpleEntry<>(
                                            (Subgraph.Node) selected, edge));
                            edge.setParam(KEY, "" + --count);
                            added.add(edge);
                            refreshWorkflow();
                        }
                    },
                            ButtonOption.focus(),
                            ButtonOption
                                    .icon(VaadinIcons.CHECK))
                    .withNoButton(ButtonOption.icon(VaadinIcons.CLOSE));
            prompt.getWindow().setIcon(ValidationManagerUI.SMALL_APP_ICON);
            prompt.open();
        });
        addTransition.setWidth(100, Unit.PERCENTAGE);
        addTransition.setEnabled(selected instanceof Subgraph.Node);
        controls.addComponent(addTransition);
        Button delete = new Button(TRANSLATOR.translate("general.delete"));
        delete.setEnabled(selected != null);
        delete.setWidth(100, Unit.PERCENTAGE);
        delete.addClickListener(listener -> {
            MessageBox prompt = MessageBox.createQuestion()
                    .withCaption(TRANSLATOR.translate("general.delete"))
                    .withMessage(TRANSLATOR.translate("general.delete.confirmation"))
                    .withYesButton(() -> {
                        if (selected instanceof Subgraph.Edge) {
                            Subgraph.Edge edge = (Subgraph.Edge) selected;
                            edges.remove(edge.getParam("label"));
                            addToDelete(edge);
                        } else {
                    Graph.Node node = (Graph.Node) selected;
                    addToDelete(node);
                }
                refreshWorkflow();
                    },
                            ButtonOption.focus(),
                            ButtonOption
                                    .icon(VaadinIcons.CHECK))
                    .withNoButton(ButtonOption.icon(VaadinIcons.CLOSE));
            prompt.getWindow().setIcon(ValidationManagerUI.SMALL_APP_ICON);
            prompt.open();
        });
        controls.addComponent(delete);
        Button rename = new Button(TRANSLATOR.translate("general.rename"));
        rename.setWidth(100, Unit.PERCENTAGE);
        rename.setEnabled(selected != null);
        rename.addClickListener(listener -> {
            Window w = new VMWindow(TRANSLATOR.translate("general.rename"));
            w.setWidth(25, Unit.PERCENTAGE);
            w.setHeight(25, Unit.PERCENTAGE);
            UI.getCurrent().addWindow(w);
        });
        controls.addComponent(rename);
        Button save = new Button(TRANSLATOR.translate("general.save"));
        save.setWidth(100, Unit.PERCENTAGE);
        save.setEnabled(!added.isEmpty() || !deleted.isEmpty());
        save.addClickListener(listener -> {
            List<Graph.Node> nodesToAdd = new ArrayList<>();
            List<Subgraph.Edge> edgesToAdd = new ArrayList<>();
            WorkflowServer ws
                    = new WorkflowServer(((Workflow) workflows.getValue()).getId());
            added.forEach(a -> {
                if (a instanceof Graph.Node) {
                    nodesToAdd.add((Graph.Node) a);
                } else if (a instanceof Subgraph.Edge) {
                    edgesToAdd.add((Subgraph.Edge) a);
                }
            });
            deleted.forEach(a -> {
                LOG.log(Level.INFO, "Deleted: {0}", a);
            });
            nodesToAdd.forEach(node -> {
                try {
                    ws.addStep(node.getParam(ITEM_NAME));
                } catch (VMException ex) {
                    LOG.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
                }
            });
            displayWorkflow(ws.getEntity());
        });
        controls.addComponent(save);
        Button cancel = new Button(TRANSLATOR.translate("general.cancel"));
        cancel.setWidth(100, Unit.PERCENTAGE);
        cancel.setEnabled(selected != null);
        cancel.addClickListener(listener -> {
            Workflow w = (Workflow) workflows.getValue();
            if (w != null) {
                displayWorkflow(w);
            }
            deleted.clear();
            added.clear();
        });
        controls.addComponent(cancel);
        return controls;
    }

    /**
     * Create workflow from database
     *
     * @param w workflow to create from
     */
    private void displayWorkflow(Workflow w) {
        Graph graph = new Graph(w.getWorkflowName(), Graph.DIGRAPH);
        nodes.clear();
        //Create the nodes
        w.getWorkflowStepList().forEach(step -> {
            addStep(step, graph);
            //Now add the links
            step.getSourceTransitions().forEach(t -> {
                addStep(t.getWorkflowStepSource(), graph);
                addStep(t.getWorkflowStepTarget(), graph);
                Subgraph.Edge edge
                        = graph.addEdge(nodes.get(t.getWorkflowStepSource()
                                .getWorkflowStepPK().getId()),
                                nodes.get(t.getWorkflowStepTarget()
                                        .getWorkflowStepPK().getId()));
                edge.setParam("label", TRANSLATOR.translate(t.getTransitionName()));
                //Workaround https://github.com/pontusbostrom/VaadinGraphvizComponent/issues/9
                edge.setDest(nodes.get(t.getWorkflowStepTarget()
                        .getWorkflowStepPK().getId()));
                edges.put(TRANSLATOR.translate(t.getTransitionName()),
                        new AbstractMap.SimpleEntry<>(
                                nodes.get(t.getWorkflowStepSource()
                                        .getWorkflowStepPK().getId()), edge));
            });
        });
        diagram.drawGraph(graph);
    }

    /**
     * Recreate graph with the edited values
     */
    private void refreshWorkflow() {
        Graph graph = new Graph(((Workflow) workflows.getValue())
                .getWorkflowName(), Graph.DIGRAPH);
        nodes.values().forEach(node -> {
            graph.addNode(node);
        });
        edges.values().forEach(edge -> {
            graph.addEdge(edge.getKey(), edge.getValue().getDest());
        });
        diagram.drawGraph(graph);
        selected = null;
        updateControls();
    }

    private void addStep(WorkflowStep step, Graph g) {
        if (!nodes.containsKey(step.getWorkflowStepPK().getId())) {
            Graph.Node node
                    = new Graph.Node(TRANSLATOR.translate(step.getStepName()));
            nodes.put(step.getWorkflowStepPK().getId(), node);
            node.setParam(KEY, "" + step.getWorkflowStepPK().getId());
            g.addNode(node);
        }
    }

    private Component getList() {
        BeanItemContainer<Workflow> container
                = new BeanItemContainer<>(Workflow.class,
                        new WorkflowJpaController(DataBaseManager
                                .getEntityManagerFactory())
                                .findWorkflowEntities());
        workflows.setContainerDataSource(container);
        workflows.getItemIds().forEach(id -> {
            Workflow temp = ((Workflow) id);
            workflows.setItemCaption(id,
                    TRANSLATOR.translate(temp.getWorkflowName()));
        });
        workflows.setNullSelectionAllowed(false);
        workflows.addValueChangeListener(listener -> {
            Workflow w = (Workflow) workflows.getValue();
            if (w != null) {
                displayWorkflow(w);
            }
            updateControls();
        });
        workflows.setSizeFull();
        return workflows;
    }

    private void updateControls() {
        bl.removeComponent(Constraint.EAST);
        bl.addComponent(getControls(), Constraint.EAST);
    }

    private void addToDelete(Object obj) {
        LOG.log(Level.INFO, "Adding to delete list: {0}", obj);
        deleted.add(obj);
    }

    private void addToAdd(Object obj) {
        LOG.log(Level.INFO, "Adding to add list: {0}", obj);
        added.add(obj);
    }
}


/*
 * 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;

import com.vaadin.data.Property;
import com.vaadin.ui.Component;
import com.vaadin.ui.HasComponents;
import com.vaadin.ui.UI;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * {@code VaadinUtils} offers some utility functions for the
 * Vaadin UI Framework.
 *
 * @author Javier Ortiz Bultron
 * Based on code from: Ronald K. Muller
 * https://gist.github.com/rmuller/10980706
 */
public final class VaadinUtils {

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

    // Utility class
    private VaadinUtils() {
    }

    /**
     * Change all {@code Locale} dependant properties of the
     * {@code com.vaadin.ui.Component}s within of the given component container
     * (typically an {@link UI} or other top level layout component). If the
     * specified {@code Locale} is the same as the current {@code Locale} of the
     * component container, this method does nothing. Otherwise it'll go thru
     * the components searching for it's component id. If it is in the resource
     * bundle, it'll set it's caption to the right translated string.
     *
     *

     * To use this method, do something like:
     *

     * public class MyUI extends UI {
     *
     *     {@literal @}Override
     *     public void init(final VaadinRequest request) {
     *         // ... usual code
     *         // somewhere in the UI the user can change the "Form Locale". This code must
     *         // call myUI#setLocale(newLocale);
     *     }
     *
     *     // ...
     *
     * }
     *
     *      String key = "demo.tab.message";
     *      VerticalLayout vl = new VerticalLayout();
     *      Button b = new Button(key);
     *      vl.addComponent(b);
     *      ResourceBundle rb = ResourceBundle.getBundle(
     *              "resource.bundle",
     *              new Locale("es"));
     *      VaadinUtils.updateLocale(vl, new Locale("es"), rb);
     *
     *      It also works with components implementing Property:
     *
     *      VerticalLayout vl = new VerticalLayout();
     *      Label l = new Label(key);
     *      vl.addComponent(l);
     *      ResourceBundle rb = ResourceBundle.getBundle(
     *              "resource.bundle",
     *              new Locale("es"));
     *      VaadinUtils.updateLocale(vl, new Locale("es"), rb);
     *

     *
     * @param ui The component container for which the {@code Locale} dependent
     * component properties must be changed, never {@code null}
     * @param locale The new {@code Locale}, never {@code null}
     * @param rb The {@code ResourceBundle} for the specified {@code Locale},
     * never {@code null}
     */
    public static void updateLocale(final HasComponents ui, final Locale locale,
            final ResourceBundle rb) {

        // locale may not be null, however the current UI Locale may be null!
        if (locale.equals(ui.getLocale())) {
            return;
        }
        final long time = System.currentTimeMillis();
        walkComponentTree(ui, (Component c) -> {
            String id = c.getId();
            String caption;
            if (c instanceof Property
                    && ((Property) c).getValue() instanceof String) {
                caption = (String) ((Property) c).getValue();
            } else {
                caption = c.getCaption();
            }
            if (id != null && !id.trim().isEmpty()) {
                if (rb.containsKey(id)) {
                    try {
                        c.setCaption(new String(rb.getString(id)
                                .getBytes("ISO-8859-1"), "UTF-8"));
                    }
                    catch (UnsupportedEncodingException ex) {
                        LOG.log(Level.SEVERE, null, ex);
                    }
                }
            } else if (caption != null && !caption.trim().isEmpty()) {
                /**
                 * This is a more complex scenario where the caption uses more
                 * than one key for translation. Sort the keys in reverse so
                 * substitutions are correct.
                 */
                final SortedSet<String> ss = new TreeSet<>(Collections.reverseOrder());
                for (Enumeration<String> e = rb.getKeys(); e.hasMoreElements();) {
                    try {
                        String key = e.nextElement();
                        ss.add(key);
                        caption = caption.replaceAll(key, new String(rb.getString(key)
                                .getBytes("ISO-8859-1"), "UTF-8"));
                    }
                    catch (UnsupportedEncodingException ex) {
                        LOG.log(Level.SEVERE, null, ex);
                    }
                }
                if (c instanceof Property) {
                    ((Property) c).setValue(caption);
                } else {
                    c.setCaption(caption);
                }
            }
        });
        LOG.log(Level.FINE, "Locale updated: {0} -> {1} in {2} ms.",
                new Object[]{ui.getLocale(), locale,
                    System.currentTimeMillis() - time});
    }

    // private
    // if switching to Java 8, remove this and replace by java.util.funtion.Consumer
    // (and make to code more functional)
    interface Consumer<T> {

        void accept(T t);
    }

    // recursively walk the Component true
    private static void walkComponentTree(Component c, Consumer<Component> visitor) {
        visitor.accept(c);
        if (c instanceof HasComponents) {
            for (Component child : ((HasComponents) c)) {
                walkComponentTree(child, visitor);
            }
        }
    }
}


/*
 * 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.importer;

import com.vaadin.ui.Upload;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Javier Ortiz Bultron javier.ortiz.78@gmail.com
 */
public class FileUploader implements Upload.Receiver {

    private File file;         // File to write to.
    private static final Logger LOG
            = Logger.getLogger(FileUploader.class.getName());

    // Callback method to begin receiving the upload.
    @Override
    public OutputStream receiveUpload(String filename,
            String MIMEType) {
        FileOutputStream fos; // Output stream to write to
        try {
            file = File.createTempFile("upload",
                    filename.substring(filename.lastIndexOf('.')));
            // Open the file for writing.
            fos = new FileOutputStream(getFile());
        } catch (FileNotFoundException ex) {
            // Error while opening the file. Not reported here.
            LOG.log(Level.SEVERE, null, ex);
            return null;
        } catch (IOException ex) {
            // Error while opening the file. Not reported here.
            LOG.log(Level.SEVERE, null, ex);
            return null;
        }
        return fos; // Return the output stream to write to
    }

    /**
     * @return the file
     */
    public File getFile() {
        return file;
    }
}


package com.blockscore.models;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * The details model used by {@link Person}.
 */
public class PersonDetails {
  @Nullable
  @JsonProperty("address")
  private String addressMatch;

  @Nullable
  @JsonProperty("address_risk")
  private String addressRisk;

  @Nullable
  @JsonProperty("identification")
  private String identficationMatch;

  @Nullable
  @JsonProperty("date_of_birth")
  private String dateOfBirthMatch;

  @NotNull
  @JsonProperty("ofac")
  private String ofacMatch;

  @NotNull
  @JsonProperty("pep")
  private String pepMatch;

  /**
   * Assesses the address match strength.
   *
   * @return the match strength
   */
  @Nullable
  public MatchRating getAddressMatchDetails() {
    return MatchRating.toEnum(addressMatch);
  }

  /**
   * Gets the risk of this particular address.
   *
   * @return the risk factor
   */
  @Nullable
  public ResultStrength getAddressRisk() {
    if (addressRisk == null) {
      return null;
    }
    return ResultStrength.toEnum(addressRisk.toLowerCase());
  }

  /**
   * Assesses the match for identity.
   *
   * @return Identity match rating
   */
  @Nullable
  public MatchRating getIdentificationMatch() {
    return MatchRating.toEnum(identficationMatch);
  }

  /**
   * Assesses the date of birth match.
   *
   * @return thee of birth match rating
   */
  @Nullable
  public MatchRating getDateOfBirthMatch() {
    return MatchRating.toEnum(dateOfBirthMatch);
  }

  /**
   * Assesses the person for placement on the OFAC.
   *
   * @return the OFAC match rating
   */
  @Nullable
  public MatchRating getOfac() {
    return MatchRating.toEnum(ofacMatch);
  }

  /**
   * Assesses the person for placement on the PEP.
   *
   * @return the PEP match rating
   */
  @Nullable
  public MatchRating getPep() {
    return MatchRating.toEnum(pepMatch);
  }
}


package com.buschmais.jqassistant.plugin.common.api.scanner;

import java.util.function.Function;

import com.buschmais.jqassistant.core.scanner.api.ScannerContext;
import com.buschmais.jqassistant.core.store.api.model.Descriptor;
import com.buschmais.jqassistant.plugin.common.api.model.FileDescriptor;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

/**
 * Abstract base class for {@link FileResolver}s.
 *

 * Provides utility functionality.
 */
public abstract class AbstractFileResolver implements FileResolver {

    private Cache<String, FileDescriptor> cache = Caffeine.newBuilder().softValues().build();

    @Override
    public <D extends FileDescriptor> D require(String requiredPath, Class<D> type, ScannerContext context) {
        return require(requiredPath, requiredPath, type, context);
    }

    /**
     * Takes an optional descriptor and transforms it to file descriptor.
     *
     * @param descriptor
     *            The descriptor, if null a new descriptor is created.
     * @param type
     *            The required type.
     * @param path
     *            The path (to set as file name).
     * @param context
     *            The scanner context.
     * @param <D>
     *            The required type.
     * @return The file descriptor.
     * @deprecated migrate to
     *             {@link #getOrCreateAs(String, Class, Function, ScannerContext)}.
     */
    @Deprecated
    protected <D extends FileDescriptor> D toFileDescriptor(Descriptor descriptor, Class<D> type, String path, ScannerContext context) {
        if (descriptor == null) {
            D result = context.getStore().create(type);
            result.setFileName(path);
            return result;
        }
        return migrateOrCast(descriptor, type, context);
    }

    /**
     * Get an existing {@link FileDescriptor} or create a new one. If an existing
     * {@link FileDescriptor} exists it will be migrated on demand.
     *
     * @param path
     *            The path.
     * @param type
     *            The requested type.
     * @param existing
     *            A {@link Function} to resolve an existing {@link FileDescriptor}.
     * @param context
     *            The {@link ScannerContext}.
     * @param <D>
     *            The requested type.
     * @return The {@link FileDescriptor}.
     */
    protected <D extends FileDescriptor> D getOrCreateAs(String path, Class<D> type, Function<String, FileDescriptor> existing, ScannerContext context) {
        FileDescriptor descriptor = cache.get(path, p -> {
            FileDescriptor fileDescriptor = existing.apply(p);
            if (fileDescriptor != null) {
                return fileDescriptor;
            }
            fileDescriptor = context.getStore().create(type);
            fileDescriptor.setFileName(path);
            return fileDescriptor;
        });
        return migrateOrCast(descriptor, type, context);
    }

    /**
     * Ensures if the given {@link FileDescriptor} implements the requested type by
     * migrating or just casting it.
     *
     * @param descriptor
     *            The {@link FileDescriptor}.
     * @param type
     *            The requested type.
     * @param context
     *            The {@link ScannerContext}.
     * @param <D>
     *            The requested type.
     * @return The {@link FileDescriptor} that implements the requested type.
     */
    private <D extends FileDescriptor> D migrateOrCast(Descriptor descriptor, Class<D> type, ScannerContext context) {
        return type.isAssignableFrom(descriptor.getClass()) ? type.cast(descriptor) : context.getStore().addDescriptorType(descriptor, type);
    }

}


package com.blockscore.models.error;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import retrofit.RetrofitError;

/**
 * Blockscore Error model.
 */
public class BlockscoreError {
  @NotNull
  @JsonProperty("error")
  private RequestError requestError;

  /**
   * Converts a Retrofit Error into a Blockscore Error.
   *
   * @param cause  the Retrofit error to convert
   * @return the Blockscore Error
   */
  @Nullable
  public static BlockscoreError getBlockscoreError(@NotNull final RetrofitError cause) {
    Object rawError = cause.getBodyAs(BlockscoreError.class);
    if (rawError instanceof BlockscoreError) {
      return (BlockscoreError) rawError;
    } else {
      return null;
    }
  }

  /**
   * Returns the error details.
   *
   * @return the error details
   */
  @NotNull
  public RequestError getError() {
    return requestError;
  }
}


package com.blockscore.models;

import com.blockscore.models.base.BasicResponse;
import com.blockscore.net.BlockscoreRestAdapter;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.List;

/**
 * The model representing question sets.
 */
public class QuestionSet extends BasicResponse {
  @NotNull
  @JsonProperty("person_id")
  private String personId;

  @JsonProperty("score")
  private Integer score;

  @JsonProperty("expired")
  private boolean expired;

  @JsonProperty("time_limit")
  private Long timeLimit;

  @NotNull
  @JsonProperty("questions")
  private List<Question> questions;

  private BlockscoreRestAdapter restAdapter;

  /**
   * Scores a question set.
   *
   * @param answers  the answers to the QuestionSet
   */
  @NotNull
  public void score(@NotNull final AnswerSet answers) {
    QuestionSet scoredSet = restAdapter.scoreQuestionSet(getId(), answers);
    expired = scoredSet.isExpired();
    score = scoredSet.getScore();
  }

  void setAdapter(BlockscoreRestAdapter restAdapter) {
    this.restAdapter = restAdapter;
  }

  /**
   * The associated person's ID.
   *
   * @return the person ID
   */
  @NotNull
  public String getPersonId() {
    return personId;
  }

  /**
   * The percentage (from 0.0 - 100.0) result of scoring the question set's answers.
   *
   * @return the score
   */
  public Integer getScore() {
    return score;
  }

  /**
   * Indicates whether the `time_limit` has been passed since the creation of the question set.
   *
   * @return true if expired
   */
  public boolean isExpired() {
    return expired;
  }

  /**
   * Gets the number of seconds after the creation of the question set before the `expired` boolean
   * will switch to `true`.
   *
   * @return the time limit
   */
  public Long getTimeLimit() {
    return timeLimit;
  }

  /**
   * Returns the list of questions to use.
   *
   * @return the questions available
   */
  @NotNull
  public List<Question> getQuestions() {
    return Collections.unmodifiableList(questions);
  }
}


package com.buschmais.jqassistant.plugin.common.api.scanner;

import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.xml.bind.DatatypeConverter;

import com.buschmais.jqassistant.plugin.common.api.model.MD5Descriptor;

/**
 * A delegate around reading input streams for calculating a MD5 hash sum.
 */
public class MD5DigestDelegate {

    /**
     * Defines the read operation to execute.
     *
     * @param <D>
     *            The MD5 descriptor type.
     */
    public interface DigestOperation<D extends MD5Descriptor> {

        /**
         * Execute the operation.
         *
         * @param inputStream
         *            The input stream to use for calculating the MD5 hash sum.
         * @return The MD5 descriptor.
         * @throws IOException
         *             If reading fails.
         */
        D execute(InputStream inputStream) throws IOException;

    }

    private static final MD5DigestDelegate instance = new MD5DigestDelegate();

    private MessageDigest md5Digest;

    /**
     * Private constructor.
     */
    private MD5DigestDelegate() {
        try {
            md5Digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("Cannot create message digest for MD5", e);
        }
    }

    /**
     * Return the singleton instance.
     *
     * @return The instance.
     */
    public static MD5DigestDelegate getInstance() {
        return instance;
    }

    /**
     * Calculate the MD5 hash sum for the given input stream using the given
     * operation.
     *
     * @param stream
     *            The stream.
     * @param digestOperation
     *            The operation.
     * @param <D>
     *            The MD5 descriptor type.
     * @return The MD5 descriptor.
     * @throws IOException
     *             If reading the stream fails.
     */
    public <D extends MD5Descriptor> D digest(InputStream stream, DigestOperation<D> digestOperation) throws IOException {
        DigestInputStream digestInputStream = new DigestInputStream(stream, md5Digest);
        D md5Descriptor = digestOperation.execute(digestInputStream);
        String md5 = DatatypeConverter.printHexBinary(md5Digest.digest());
        md5Descriptor.setMd5(md5);
        return md5Descriptor;
    }
}


package com.buschmais.jqassistant.plugin.common.api.scanner.filesystem;

import java.util.HashSet;
import java.util.Set;

import com.buschmais.jqassistant.core.shared.annotation.ToBeRemovedInVersion;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.lang3.StringUtils;

/**
 * A matcher for file patterns.
 *
 * Holds patters for file paths to be included or excluded and provides an
 * {@link #accepts(String)} method which evaluates a given path.
 */
public class FilePatternMatcher {

    private Set<String> includeFilePatterns = null;
    private Set<String> excludeFilePatterns = null;

    private FilePatternMatcher() {
    }

    /**
     * Determines if the given path matches the configured include and exclude
     * patterns.
     *
     * NOTE: The include pattern is evaluated before the exclude pattern.
     *
     * @param path
     *            The path.
     * @return true if the path matches.
     */
    public boolean accepts(String path) {
        boolean result;
        if (includeFilePatterns != null) {
            result = matches(path, includeFilePatterns);
        } else {
            result = true;
        }
        if (excludeFilePatterns != null) {
            result = result && !matches(path, excludeFilePatterns);
        }
        return result;
    }

    private boolean matches(String path, Set<String> filePatterns) {
        for (String filePattern : filePatterns) {
            if (FilenameUtils.wildcardMatch(path, filePattern, IOCase.SENSITIVE)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Return a {@link Builder}.
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * Builder for the file pattern matcher.
     */
    public static class Builder {

        private FilePatternMatcher instance = new FilePatternMatcher();

        /**
         * Creates a new instance.
         *
         * @return The builder.
         */
        @Deprecated
        @ToBeRemovedInVersion(major = 1, minor = 8)
        public static Builder newInstance() {
            return new Builder();
        }

        /**
         * Configures a list of file name patterns to include.
         *
         * @param patternList
         *            The comma separated list of file name patterns to include.
         * @return The builder.
         */
        public Builder include(String patternList) {
            instance.includeFilePatterns = parse(patternList);
            return this;
        }

        /**
         * Configures a list of file name patterns to exclude.
         *
         * @param patternList
         *            The comma separated list of file name patterns to exclude.
         * @return The builder.
         */
        public Builder exclude(String patternList) {
            instance.excludeFilePatterns = parse(patternList);
            return this;
        }

        /**
         * Returns the configured matcher instance.
         *
         * @return The matcher instance.
         */
        public FilePatternMatcher build() {
            return instance;
        }

        private Set<String> parse(String patternList) {
            if (patternList == null) {
                return null;
            }
            Set<String> patterns = new HashSet<>();
            for (String pattern : patternList.split(",")) {
                String filePattern = pattern.trim();
                if (StringUtils.isNotEmpty(filePattern)) {
                    patterns.add(filePattern);
                }
            }
            return patterns;
        }
    }
}


package com.blockscore.models;

import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.util.ArrayList;
import java.util.List;

/**
 * The model representing a set of answered questions used for scoring a {@link QuestionSet}.
 */
public class AnswerSet {
  @JsonProperty("answers")
  private List<QuestionAnswerPair> answers;

  public AnswerSet() {
    answers = new ArrayList<QuestionAnswerPair>();
  }

  /**
   * Adds an answer to a question to the AnswerSet.
   *
   * @param questionId  the id of the question to be answered
   * @param answerId  the id of the answer selected
   */
  public void addAnswer(int questionId, int answerId) {
    QuestionAnswerPair answerPair = new QuestionAnswerPair(questionId, answerId);
    answers.add(answerPair);
  }

  private static class QuestionAnswerPair {
    @SuppressFBWarnings("URF_UNREAD_FIELD")
    @JsonProperty("question_id")
    private int questionId;

    @SuppressFBWarnings("URF_UNREAD_FIELD")
    @JsonProperty("answer_id")
    private int answerId;

    private QuestionAnswerPair() {
      // Do nothing. No-argument constructor required for Retrofit.
    }

    public QuestionAnswerPair(int questionId, int answerId) {
      this.questionId = questionId;
      this.answerId = answerId;
    }
  }
}


package com.blockscore.models;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * Model representing a watchlist hit.
 */
public class WatchlistHit {
  @NotNull
  @JsonProperty("watchlist_name")
  private String watchlist;

  @NotNull
  @JsonProperty("entry_type")
  private String entryType;

  @Nullable
  @JsonProperty("matching_info")
  private String[] matchingInfo;

  @NotNull
  @JsonProperty("confidence")
  private Double confidence;

  @Nullable
  @JsonProperty("url")
  private String url;

  @Nullable
  @JsonProperty("notes")
  private String notes;

  @Nullable
  @JsonProperty("title")
  private String title;

  @NotNull
  @JsonProperty("name_full")
  private String fullName;

  @Nullable
  @JsonProperty("alternate_names")
  private String alternateNames;

  @Nullable
  @JsonProperty("date_of_birth")
  private Date dateOfBirth;

  @Nullable
  @JsonProperty("passport")
  private String passportNumbers;

  @Nullable
  @JsonProperty("ssn")
  private String ssn;

  @Nullable
  @JsonProperty("address_street1")
  private String addressStreet1;

  @Nullable
  @JsonProperty("address_street2")
  private String addressStreet2;

  @Nullable
  @JsonProperty("address_city")
  private String addressCity;

  @Nullable
  @JsonProperty("address_state")
  private String addressState;

  @Nullable
  @JsonProperty("address_postal_code")
  private String addressPostalCode;

  @Nullable
  @JsonProperty("address_country_code")
  private String addressCountryCode;

  @Nullable
  @JsonProperty("address_raw")
  private String rawAddress;

  @NotNull
  @JsonProperty("names")
  private List<NameResult> names;

  @NotNull
  @JsonProperty("births")
  private List<BirthRange> births;

  @NotNull
  @JsonProperty("documents")
  private List<Document> documents;

  @NotNull
  @JsonProperty("addresses")
  private List<Address> addresses;

  /**
   * Gets the watchlist on which this match took place.
   *
   * @return the watchlist
   */
  @NotNull
  public String getWatchlist() {
    return watchlist;
  }

  /**
   * Returns the entry type of this watchlist hit.
   *
   * @return the entry type
   */
  @NotNull
  public EntityType getEntryType() {
    return EntityType.toEnum(entryType);
  }

  /**
   * Gets a list of elements in your request that match this watchlist hit.
   *
   * @return an array of strings containing the matching info
   */
  @NotNull
  public String[] getMatchingInfo() {
    if (matchingInfo == null) {
      return new String[0];
    }

    return Arrays.copyOf(matchingInfo, matchingInfo.length);
  }

  /**
   * Gets the confidence rating (between 0 and 1.0).
   *
   * @return the confidence value
   */
  public double getConfidence() {
    return confidence;
  }

  /**
   * Returns the url for this candidate.
   *
   * @return the url
   */
  @Nullable
  public String getUrl() {
    return url;
  }

  /**
   * Returns the notes for this candidate.
   *
   * @return the notes data
   */
  @Nullable
  public String getNotes() {
    return notes;
  }

  /**
   * Returns the title for this candidate.
   *
   * @return the title
   */
  @Nullable
  public String getTitle() {
    return title;
  }

  /**
   * Returns the full name for this candidate.
   *
   * @return the full name
   */
  @Nullable
  public String getName() {
    return fullName;
  }

  /**
   * Returns the set of alternate names of a candidate.
   *
   * @return the array of alternate names, not null
   */
  @NotNull
  public String getAlternateNames() {
    return alternateNames;
  }

  /**
   * Returns the candidate's date of birth.
   *
   * @return the date of birth
   */
  @Nullable
  public Date getDateOfBirth() {
    if (dateOfBirth == null) {
      return null;
    }

    return new Date(dateOfBirth.getTime());
  }

  /**
   * Gets the ssn for this candidate.
   *
   * @return the ssn
   */
  @Nullable
  public String getSsn() {
    return ssn;
  }

  /**
   * Gets the list of passport numbers for a candidate.
   *
   * @return the array of passport numbers
   */
  @Nullable
  public String getPassports() {
    return passportNumbers;
  }

  /**
   * Gets the address of the candidate.
   *
   * @return the address
   */
  @Nullable
  public Address getAddress() {
    return new Address(addressStreet1,
                       addressStreet2,
                       addressCity,
                       addressState,
                       addressPostalCode,
                       addressCountryCode);
  }

  /**
   * Returns the address of this candidate in raw form.
   *
   * @return the address in raw form
   */
  @Nullable
  public String getRawAddress() {
    return rawAddress;
  }

  /**
   * Returns the list of names matched against this candidate.
   *
   * @return the list of names
   */
  @NotNull
  public List<NameResult> getNames() {
    return Collections.unmodifiableList(names);
  }

  /**
   * Returns the list of date of birth ranges matched against this candidate.
   *
   * @return the list of birth ranges
   */
  @NotNull
  public List<BirthRange> getBirths() {
    return Collections.unmodifiableList(births);
  }

  /**
   * Returns the list of documents matched against this candidate.
   *
   * @return the list of documents
   */
  @NotNull
  public List<Document> getDocuments() {
    return Collections.unmodifiableList(documents);
  }

  /**
   * Gets the addresses from the watchlist.
   *
   * @return the list of addresses
   */
  @NotNull
  public List<Address> getAddresses() {
    return Collections.unmodifiableList(addresses);
  }
}


package com.blockscore.models;

import com.blockscore.models.base.BasicResponse;
import com.blockscore.net.BlockscoreApiClient;
import com.blockscore.net.BlockscoreRestAdapter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The person model.
 */
public class Person extends BasicResponse {
  @JsonIgnore
  private BlockscoreRestAdapter restAdapter;

  // Request Fields
  @NotNull
  @JsonProperty("name_first")
  private String firstName;

  @Nullable
  @JsonProperty("name_middle")
  private String middleName;

  @NotNull
  @JsonProperty("name_last")
  private String lastName;

  @NotNull
  @JsonProperty("document_type")
  private String documentType;

  @NotNull
  @JsonProperty("document_value")
  private String documentValue;

  @NotNull
  @JsonProperty("birth_day")
  private Integer birthDay;

  @NotNull
  @JsonProperty("birth_month")
  private Integer birthMonth;

  @NotNull
  @JsonProperty("birth_year")
  private Integer birthYear;

  @NotNull
  @JsonProperty("address_street1")
  private String addressStreet1;

  @Nullable
  @JsonProperty("address_street2")
  private String addressStreet2;

  @NotNull
  @JsonProperty("address_city")
  private String addressCity;

  @NotNull
  @JsonProperty("address_subdivision")
  private String addressSubdivision;

  @NotNull
  @JsonProperty("address_postal_code")
  private String addressPostalCode;

  @NotNull
  @JsonProperty("address_country_code")
  private String addressCountryCode;

  @Nullable
  @JsonProperty("phone_number")
  private String phoneNumber;

  @Nullable
  @JsonProperty("ip_address")
  private String ipAddress;

  @NotNull
  @JsonProperty("note")
  private String note;
  @NotNull

  // Response Fields
  @JsonProperty("status")
  private String status;

  @NotNull
  @JsonProperty("details")
  private PersonDetails details;

  @NotNull
  @JsonProperty("question_sets")
  private List<String> questionSetIds;

  private Person() {
    // Restricts access to end user so they must use a Person.Builder to create a Person
  }

  /**
   * Sets the internal REST api adapter needed to complete Blockscore API requests.
   *
   * @param restAdapter  the REST adapter
   */
  public void setAdapter(BlockscoreRestAdapter restAdapter) {
    this.restAdapter = restAdapter;
  }

  /**
   * Creates a question set with no time limit.
   *
   * @return the new question set
   */
  @NotNull
  public QuestionSet createQuestionSet() {
    return createQuestionSet(0L);
  }

  /**
   * Creates a question set with a set time limit in seconds.
   *
   * @param timeLimit  the time limit
   * @return the new question set
   */
  public QuestionSet createQuestionSet(long timeLimit) {
    Map<String, String> queryOptions = new HashMap<String, String>();
    queryOptions.put("person_id", getId());
    queryOptions.put("time_limit", String.valueOf(timeLimit));

    QuestionSet questionSet = restAdapter.createQuestionSet(queryOptions);
    questionSet.setAdapter(restAdapter);
    return questionSet;
  }

  /**
   * Retrieve a question set you have created.
   *
   * @param questionSetId  Question set ID
   * @return the retrieved question set
   */
  public QuestionSet retrieveQuestionSet(@NotNull final String questionSetId) {
    QuestionSet questionSet = restAdapter.retrieveQuestionSet(questionSetId);
    questionSet.setAdapter(restAdapter);
    return questionSet;
  }

  /**
   * Gets the first name.
   *
   * @return the first name
   */
  @NotNull
  public String getFirstName() {
    return firstName;
  }

  /**
   * Gets the middle name. (Optional)
   *
   * @return the middle name
   */
  @Nullable
  public String getMiddleName() {
    return middleName;
  }

  /**
   * Gets the last name.
   *
   * @return the last name
   */
  @NotNull
  public String getLastName() {
    return lastName;
  }

  /**
   * Gets the identifying document type.
   *
   * @return the document type
   */
  @NotNull
  public String getDocumentType() {
    return this.documentType;
  }

  /**
   * Gets the identifying document value.
   *
   * @return the document value
   */
  @NotNull
  public String getDocumentValue() {
    return this.documentValue;
  }

  /**
   * Gets the date of birth for this individual.
   *
   * @return the date of birth
   */
  @NotNull
  public Date getDateOfBirth() {
    GregorianCalendar calendar = new GregorianCalendar(birthYear, birthMonth, birthDay);
    return calendar.getTime();
  }

  /**
   * Gets the address for this individual.
   *
   * @return the address
   */
  @NotNull
  public Address getAddress() {
    Address addressObject = new Address(addressStreet1,
                      addressStreet2,
                      addressCity,
                      addressSubdivision,
                      addressPostalCode,
                      addressCountryCode);
    return addressObject;
  }

  /**
   * Gets phone number of the individual (if available).
   *
   * @return the phone number
   */
  @Nullable
  public String getPhoneNumber() {
    return phoneNumber;
  }

  /**
   * Gets the IP address for this person. (if available)
   *
   * @return the IP address
   */
  @Nullable
  public String getIpAddress() {
    return ipAddress;
  }

  /**
   * Gets any note data you have associated with the Person.
   *
   * @return the stored note data
   */
  @Nullable
  public String getNote() {
    return note;
  }

  /**
   * Returns either valid or invalid and is the culmination of whether or not the passed
   * in information is valid against various databases and signals.
   *
   * @return true if valid
   */
  public boolean isValid() {
    return status.equalsIgnoreCase("valid");
  }

  /**
   * Contains a breakdown of how the status (validity) was determined. It will let you diagnose
   * problems like address inconsistencies.
   *
   * @return the details breakdown
   */
  @NotNull
  public PersonDetails getDetails() {
    return details;
  }

  /**
   * Gets the question set ids associated with this Person record.
   *
   * @return the question sets
   */
  @NotNull
  public List<String> getQuestionSetIds() {
    return Collections.unmodifiableList(questionSetIds);
  }

  /**
   * The builder used for constructing a {@link Person}.
   */
  public static class Builder {
    private BlockscoreRestAdapter restAdapter;
    private Map<String, String> queryOptions;

    public Builder(BlockscoreApiClient client) {
      this.restAdapter = client.getAdapter();
      queryOptions = new HashMap<String, String>();
    }

    /**
     * Sets the legal first name of the customer.
     *
     * @param firstName  the legal first name
     * @return this
     */
    @NotNull
    public Builder setFirstName(@NotNull final String firstName) {
      queryOptions.put("name_first", firstName);
      return this;
    }

    /**
     * Sets the  legal middle name of the customer (optional).
     *
     * @param middleName  the legal middle name
     * @return this
     */
    @NotNull
    public Builder setMiddleName(@Nullable final String middleName) {
      queryOptions.put("name_middle", middleName);
      return this;
    }

    /**
     * Sets the legal last name of the customer.
     *
     * @param lastName  the legal last name
     * @return this
     */
    @NotNull
    public Builder setLastName(@NotNull final String lastName) {
      queryOptions.put("name_last", lastName);
      return this;
    }

    /**
     * Sets the identifying document type.
     *
     * @param documentType  the document type
     * @return this
     */
    @NotNull
    public Builder setDocumentType(@NotNull final String documentType) {
      queryOptions.put("document_type", documentType);
      return this;
    }

    /**
     * Sets the identifying document value.
     *
     * @param documentValue  the document value
     * @return this
     */
    @NotNull
    public Builder setDocumentValue(@NotNull final String documentValue) {
      queryOptions.put("document_value", documentValue);
      return this;
    }

    /**
     * Sets the date of birth.
     *
     * @param dateOfBirth  the date of birth
     * @return this
     */
    @NotNull
    public Builder setDateOfBirth(@NotNull final Date dateOfBirth) {
      Calendar calendar = new GregorianCalendar();
      calendar.setTime(dateOfBirth);

      queryOptions.put("birth_day", String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)));
      queryOptions.put("birth_month", String.valueOf(calendar.get(Calendar.MONTH) + 1)); // Months begin at 0
      queryOptions.put("birth_year", String.valueOf(calendar.get(Calendar.YEAR)));

      return this;
    }

    /**
     * Sets the person's address.
     *
     * @param address  the address
     * @return this
     */
    @NotNull
    public Builder setAddress(@NotNull final Address address) {
      queryOptions.put("address_street1", address.getStreet1());
      queryOptions.put("address_street2", address.getStreet2());
      queryOptions.put("address_city", address.getCity());
      queryOptions.put("address_subdivision", address.getSubdivision());
      queryOptions.put("address_postal_code", address.getPostalCode());
      queryOptions.put("address_country_code", address.getCountryCode());
      return this;
    }

    /**
     * Sets a person's phone number.
     *
     *

     * If you set the phone number, we will use it as an additional
     * 'positive' data point for the consumer. That is, if it is provided, it will help us identify
     * them, but if we cannot, they will not be penalized.
     *
     * @param phoneNumber  the phone number for this individual.
     * @return this
     */
    @NotNull
    public Builder setPhoneNumber(@Nullable final String phoneNumber) {
      queryOptions.put("phone_number", phoneNumber);
      return this;
    }

    /**
     * Sets a person's IP address.
     *
     *

     * Your customers' IP address can be passed to us for storage
     * purposes. Soon we will be using this information for anti-fraud and verification purposes.
     * With this information we will be able to back-test your verifications when this feature is
     * released.
     *
     * @param ipAddress  the IP address
     * @return this
     */
    @NotNull
    public Builder setIpAddress(@Nullable final String ipAddress) {
      queryOptions.put("ip_address", ipAddress);
      return this;
    }

    /**
     * You can store additional information about the person here such as your internal system's
     * identifier for this individual. This will allow you to keep track of them.
     *
     * @param note Note to store.
     * @return this
     */
    @NotNull
    public Builder setNote(@Nullable final String note) {
      queryOptions.put("note", note);
      return this;
    }

    /**
     * Creates a new {@link Person}.
     *
     * @return the new person
     */
    public Person create() {
      Person person = restAdapter.createPerson(queryOptions);
      person.setAdapter(restAdapter);
      return person;
    }
  }
}


package com.blockscore.models;

import com.blockscore.models.base.BasicResponse;
import com.blockscore.net.BlockscoreApiClient;
import com.blockscore.net.BlockscoreRestAdapter;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

/**
 * The company model.
 */
public class Company extends BasicResponse {
  // Request fields
  @NotNull
  @JsonProperty("entity_name")
  private String entityName;

  @NotNull
  @JsonProperty("tax_id")
  private String taxId;

  @Nullable
  @JsonProperty("incorporation_state")
  private String incorporationState;

  @NotNull
  @JsonProperty("incorporation_country_code")
  private String incorporationCountryCode;

  @NotNull
  @JsonProperty("incorporation_type")
  private String incorporationType;

  @Nullable
  @JsonProperty("incorporation_day")
  private Integer incorporationDay;

  @Nullable
  @JsonProperty("incorporation_month")
  private Integer incorporationMonth;

  @Nullable
  @JsonProperty("incorporation_year")
  private Integer incorporationYear;

  @Nullable
  @JsonProperty("dbas")
  private String dbas;

  @Nullable
  @JsonProperty("registration_number")
  private String registrationNumber;

  @Nullable
  @JsonProperty("email")
  private String email;

  @Nullable
  @JsonProperty("url")
  private String url;

  @Nullable
  @JsonProperty("phone_number")
  private String phoneNumber;

  @Nullable
  @JsonProperty("ip_address")
  private String ipAddress;

  @Nullable
  @JsonProperty("note")
  private String note;

  @NotNull
  @JsonProperty("address_street1")
  private String addressStreet1;

  @Nullable
  @JsonProperty("address_street2")
  private String addressStreet2;

  @NotNull
  @JsonProperty("address_city")
  private String addressCity;

  @NotNull
  @JsonProperty("address_subdivision")
  private String addressSubdivision;

  @NotNull
  @JsonProperty("address_postal_code")
  private String addressPostalCode;

  @NotNull
  @JsonProperty("address_country_code")
  private String addressCountryCode;

  // Response fields
  @NotNull
  @JsonProperty("details")
  private CompanyDetails details;

  @NotNull
  @JsonProperty("status")
  private String status;

  private Company() {
    // Restricts access to end user so they must use a Company.Builder to create a Person
  }

  /**
   * Gets the name of the entity.
   *
   * @return Name of the entity.
   */
  @NotNull
  public String getEntityName() {
    return entityName;
  }

  /**
   * Gets the Tax ID associated with this entity.
   *
   * @return Tax ID
   */
  @NotNull
  public String getTaxId() {
    return taxId;
  }

  /**
   * Gets the incorporation state. Can be either of ISO code form or the full length name of the state.
   *
   * @return the incorporation state
   */
  @Nullable
  public String getIncorporationState() {
    return incorporationState;
  }

  /**
   * Gets the incorporation country code. Should be of the ISO alpha-2 code form.
   *
   * @return the incorporation country code
   */
  @NotNull
  public String getIncorporationCountryCode() {
    return incorporationCountryCode;
  }

  /**
   * Gets the corporation type. The type of legal business entity that this company
   * is such as a Limited Liability Company.
   *
   * @return the corporation type
   */
  @NotNull
  public CorporationType getIncorporationType() {
    return CorporationType.toEnum(incorporationType);
  }

  /**
   * Gets the date of incorporation.
   *
   * @return the incorporation date
   */
  @Nullable
  public Date getIncorporationDate() {
    if (incorporationDay == null || incorporationMonth == null || incorporationYear == null) {
      return null;
    }

    GregorianCalendar calendarDay = new GregorianCalendar(incorporationYear, incorporationMonth, incorporationDay);
    return calendarDay.getTime();
  }

  /**
   * Gets a list of "doing business as" names, which are other names this business may be known by.
   *
   * @return the "doing business as" names
   */
  @Nullable
  public String getDbas() {
    return dbas;
  }

  /**
   * Gets the registration number. This is the number typically provided by the state of
   * incorporation which is assigned to a business. Should only include the digits of the
   * registration number with no extraneous characters like dashes.
   *
   * @return the registration number
   */
  @Nullable
  public String getRegistrationNumber() {
    return registrationNumber;
  }

  /**
   * Gets the email for this entity.
   *
   * @return the email address
   */
  @Nullable
  public String getEmail() {
    return email;
  }

  /**
   * Gets the URL for the entity.
   *
   * @return the URL
   */
  @Nullable
  public String getUrl() {
    return url;
  }

  /**
   * Gets the company's phone number.
   *
   * @return the phone number
   */
  @Nullable
  public String getPhoneNumber() {
    return phoneNumber;
  }

  /**
   * Gets a company's IP address.
   *
   * @return the IP address
   */
  @Nullable
  public String getIpAddress() {
    return ipAddress;
  }

  /**
   * Gets any note data you have associated with the Company.
   *
   * @return the note data
   */
  @Nullable
  public String getNote() {
    return note;
  }

  /**
   * Gets the address for this company.
   *
   * @return Address
   */
  @NotNull
  public Address getAddress() {
    return new Address(addressStreet1,
               addressStreet2,
               addressCity,
               addressSubdivision,
               addressPostalCode,
               addressCountryCode);
  }

  /**
   * Gets either valid or invalid and is the culmination of whether or not the passed
   * in information is valid against various databases and signals.
   *
   * @return true if valid.
   */
  public boolean isValid() {
    return status.equalsIgnoreCase("valid");
  }

  /**
   * Contains a breakdown of how the status (validity) was determined. It will let you diagnose
   * problems like address inconsistencies.
   *
   * @return the details
   */
  @Nullable
  public CompanyDetails getDetails() {
    return details;
  }

  /**
   * The builder used for constructing a {@link Company}.
   */
  public static class Builder {
    private BlockscoreRestAdapter restAdapter;
    private Map<String, String> queryOptions;

    public Builder(BlockscoreApiClient client) {
      this.restAdapter = client.getAdapter();
      queryOptions = new HashMap<String, String>();
    }

    /**
     * Name of entity. This should exclude any legal endings like "Co" or "Inc" for best results.
     *
     * @param entityName  Name
     * @return this
     */
    @NotNull
    public Builder setEntityName(@NotNull final String entityName) {
      queryOptions.put("entity_name", entityName);
      return this;
    }

    /**
     * Sets the Tax ID for this entity. The tax ID should only include the digits of the ID with
     * no extraneous characters like dashes.
     *
     * @param taxId  the tax ID for the company
     * @return this
     */
    @NotNull
    public Builder setTaxId(@NotNull final String taxId) {
      queryOptions.put("tax_id", taxId);
      return this;
    }

    /**
     * Sets the incorporation state. Can be either of ISO code form or the full length name of the state.
     *
     * @param incorporationState  the incorporation state
     * @return this
     */
    @NotNull
    public Builder setIncorporationState(@Nullable final String incorporationState) {
      queryOptions.put("incorporation_state", incorporationState);
      return this;
    }

    /**
     * Sets the incorporation country code. Should be of the ISO alpha-2 code form.
     *
     * @param incorporationCountryCode  the country code
     * @return this
     */
    @NotNull
    public Builder setIncorporationCountryCode(@NotNull final String incorporationCountryCode) {
      queryOptions.put("incorporation_country_code", incorporationCountryCode);
      return this;
    }

    /**
     * Sets the incorporation type.
     *
     * @param incorporationType  the corporation type
     * @return this
     */
    public Builder setIncorporationType(@NotNull final CorporationType incorporationType) {
      queryOptions.put("incorporation_type", String.valueOf(incorporationType));
      return this;
    }

    /**
     * Sets the incorporation date.
     *
     * @param incorporationDate  the incorporation date
     * @return this
     */
    @NotNull
    public Builder setIncorporationDate(@Nullable final Date incorporationDate) {
      if (incorporationDate == null) {
        return this;
      }

      Calendar calendar = new GregorianCalendar();
      calendar.setTime(incorporationDate);

      queryOptions.put("incorporation_day", String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)));
      queryOptions.put("incorporation_month", String.valueOf(calendar.get(Calendar.MONTH) + 1)); // Months begin at 0
      queryOptions.put("incorporation_year", String.valueOf(calendar.get(Calendar.YEAR)));

      return this;
    }

    /**
     * Sets the "doing business as" names for the company.
     * @param dbas  the doing business as names
     * @return this.
     */
    public Builder setDbas(@Nullable final String dbas) {
      queryOptions.put("dbas", dbas);
      return this;
    }

    /**
     * Sets the registration number for this entity. Should only include the digits of the
     * registration number with no extraneous characters like dashes.
     *
     * @param registrationNumber  the registration number
     * @return this
     */
    public Builder setRegistrationNumber(@Nullable final String registrationNumber) {
      queryOptions.put("registration_number", registrationNumber);
      return this;
    }

    /**
     * Sets the email for this entity. Any form of valid email is accepted.
     *
     * @param email  the email address
     * @return this
     */
    public Builder setEmail(@Nullable final String email) {
      queryOptions.put("email", email);
      return this;
    }

    /**
     * Sets the URL for this business. Can either contain protocol information or not
     * (ex. www.example.com and http://www.example.com).
     *
     * @param url  the URL
     * @return this
     */
    public Builder setUrl(@Nullable final String url) {
      queryOptions.put("url", url);
      return this;
    }

    /**
     * Sets a company's phone number. Extra characters like parenthesis and dashes are
     * accepted - can either contain the country code or not.
     *
     * @param phoneNumber  the phone number
     * @return this
     */
    @NotNull
    public Builder setPhoneNumber(@Nullable final String phoneNumber) {
      queryOptions.put("phone_number", phoneNumber);
      return this;
    }

    /**
     * Sets a company's IP address. Both IPv4 and IPv6 style IP addresses are acceptable.
     *
     * @param ipAddress  the IP address
     * @return this
     */
    @NotNull
    public Builder setIpAddress(@Nullable final String ipAddress) {
      queryOptions.put("ip_address", ipAddress);
      return this;
    }

    /**
     * Store additional information about the candidate here such as your internal system's identifier
     * for this individual. This will allow you to keep track of them.
     *
     * @param note  the additional information
     * @return this
     */
    @NotNull
    public Builder setNote(@Nullable final String note) {
      queryOptions.put("note", note);
      return this;
    }

    /**
     * Sets the company's address.
     *
     * @param address  the address
     * @return this
     */
    public Builder setAddress(@NotNull final Address address) {
      queryOptions.put("address_street1", address.getStreet1());
      queryOptions.put("address_street2", address.getStreet2());
      queryOptions.put("address_city", address.getCity());
      queryOptions.put("address_subdivision", address.getSubdivision());
      queryOptions.put("address_postal_code", address.getPostalCode());
      queryOptions.put("address_country_code", address.getCountryCode());
      return this;
    }

    /**
     * Creates a new {@link Company}.
     *
     * @return the new company
     */
    public Company create() {
      Company company = restAdapter.createCompany(queryOptions);
      return company;
    }
  }
}


package com.blockscore.models;

import com.blockscore.models.base.BasicResponse;
import com.blockscore.net.BlockscoreApiClient;
import com.blockscore.net.BlockscoreRestAdapter;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The candidate model.
 */
public class Candidate extends BasicResponse {
  @JsonIgnore
  private BlockscoreRestAdapter restAdapter;

  @NotNull
  @JsonProperty("name_first")
  private String firstName;

  @Nullable
  @JsonProperty("name_middle")
  private String middleName;

  @NotNull
  @JsonProperty("name_last")
  private String lastName;

  @Nullable
  @JsonProperty("note")
  private String note;

  @Nullable
  @JsonProperty("ssn")
  private String socialSecurityNumber;

  @Nullable
  @JsonProperty("passport")
  private String passport;

  @Nullable
  @JsonProperty("date_of_birth")
  private Date dateOfBirth;

  @NotNull
  @JsonProperty("address_street1")
  private String addressStreet1;

  @Nullable
  @JsonProperty("address_street2")
  private String addressStreet2;

  @NotNull
  @JsonProperty("address_city")
  private String addressCity;

  @NotNull
  @JsonProperty("address_subdivision")
  private String addressSubdivision;

  @NotNull
  @JsonProperty("address_postal_code")
  private String addressPostalCode;

  @NotNull
  @JsonProperty("address_country_code")
  private String addressCountryCode;

  protected Candidate() {
    // Restricts access to end user so they must use a Candidate.Builder to create a Person
  }

  /**
   * Updates this candidate.
   *
   * @return this
   */
  public Candidate save() {
    restAdapter.updateCandidate(getId(), this);
    return this;
  }

  /**
   * Deletes this candidate.
   */
  public void delete() {
    restAdapter.deleteCandidate(getId());
  }

  /**
   * Returns a complete revision history of a candidate's edits. This allows you to maintain a full
   * audit trail of when and how you update a client's profile over time. The latest revision is
   * presented at the top of the list, and the original is at the end of the list.
   * @return the list of candidates
   */
  public List<Candidate> getRevisionHistory() {
    List<Candidate> candidates = restAdapter.getCandidateHistory(getId());

    for (Candidate candidate : candidates) {
      candidate.setAdapter(restAdapter);
    }

    return Collections.unmodifiableList(candidates);
  }

  /**
   * Retrieve all historical watchlist hits for this candidate.
   * @return the paginated historical watchlist hits
   */
  public PaginatedResult<WatchlistHit> getPastHits() {
    return restAdapter.getCandidateHits(getId());
  }

  /**
   * Performs a watchlist search for this candidate with default search options.
   * Results may be of entities or individuals.
   *
   * @return the paginated watchlist hit results
   */
  public PaginatedResult<WatchlistHit> searchWatchlists() {
    return searchWatchlists(null, null);
  }

  /**
   * Performs a watchlist search for this candidate with a specified similarity threshold.
   * Results may be of entities or individuals.
   *
   * @param similarityThreshold  the tolerated similarity threshold
   * @return the paginated watchlist hit resultss
   */
  public PaginatedResult<WatchlistHit> searchWatchlists(Double similarityThreshold) {
    return searchWatchlists(null, similarityThreshold);
  }

  /**
   * Performs a watchlist search for this candidate with a specified entity type.
   * The default similarity threshold is used.
   *
   * @param entityType  the type of entity
   * @return the paginated watchlist hit results
   */
  public PaginatedResult<WatchlistHit> searchWatchlists(EntityType entityType) {
    return searchWatchlists(entityType, null);
  }

  /**
   * Performs a watchlist search for this candidate.
   *
   * @param entityType  the type of entity
   * @param similarityThreshold  the accepted threshold of similarity
   * @return the paginated watchlist hit results
   */
  public PaginatedResult<WatchlistHit> searchWatchlists(EntityType entityType, Double similarityThreshold) {
    Map<String, String> queryOptions = new HashMap<String, String>();
    queryOptions.put("candidate_id", getId());

    if (entityType != null) {
      queryOptions.put("match_type", String.valueOf(entityType));
    }

    if (similarityThreshold != null) {
      queryOptions.put("similarity_threshold", String.valueOf(similarityThreshold));
    }

    WatchlistSearchResults results = restAdapter.searchWatchlists(queryOptions);

    //wrap the result's data with PaginatedResult to make v5.0 transition simpler
    return new PaginatedResult<WatchlistHit>(results.getMatches(), results.getCount(), false);
  }

  /**
   * Sets the legal first name of the customer.
   *
   * @param firstName the first name
   * @return this
   */
  @NotNull
  public Candidate setFirstName(@NotNull final String firstName) {
    this.firstName = firstName;
    return this;
  }

   /**
   * Sets the legal middle name of the customer.
  *
   * @param middleName the middle name
   * @return this
   */
  @NotNull
  public Candidate setMiddleName(@NotNull final String middleName) {
    this.middleName = middleName;
    return this;
  }

  /**
   * Sets the legal last name.
   *
   * @param lastName the last name
   * @return this
   */
  @NotNull
  public Candidate setLastName(@NotNull final String lastName) {
    this.lastName = lastName;
    return this;
  }
  /**
   * You can store additional information about the candidate here such as your internal system's
   * identifier for this individual. This will allow you to keep track of them.
   *
   * @param note the additional information to store.]
   * @return this
   */
  @NotNull
  public Candidate setNote(@Nullable final String note) {
    this.note = note;
    return this;
  }

  /**
   * Can be either the last 4 digits of the US Social Security Number or the whole SSN.
   *
   * @param ssn  the SSN to use
   * @return this
   */
  @NotNull
  public Candidate setSsn(@Nullable final String ssn) {
    this.socialSecurityNumber = ssn;
    return this;
  }

  /**
   * Sets the passport number of the individual being verified. is only used for verifying non-US customers.
   *
   * @param passport  the passport number
   * @return this
   */
  @NotNull
  public Candidate setPassport(@Nullable final String passport) {
    this.passport = passport;
    return this;
  }

  /**
   * Set the date of birth of your candidate.
   *
   * @param dateOfBirth  the date of birth
   * @return this
   */
  @NotNull
  public Candidate setDateOfBirth(@Nullable final Date dateOfBirth) {
    if (dateOfBirth == null) {
      this.dateOfBirth = null;
      return this;
    }

    this.dateOfBirth = new Date(dateOfBirth.getTime());
    return this;
  }

  /**
   * Sets the primary street address for this person.
   *
   * @param address  the primary street address
   * @return this
   */
  public Candidate setAddress(@NotNull final Address address) {
    this.addressStreet1 = address.getStreet1();
    this.addressStreet2 = address.getStreet2();
    this.addressCity = address.getCity();
    this.addressSubdivision = address.getSubdivision();
    this.addressPostalCode = address.getPostalCode();
    this.addressCountryCode = address.getCountryCode();
    return this;
  }

  /**
   * The legal first name of the customer.
   *
   * @return the first name
   */
  @Nullable
  public String getFirstName() {
    return firstName;
  }

  /**
   * The legal middle name of the customer.
   *
   * @return the middle name
   */
  @Nullable
  public String getMiddleName() {
    return middleName;
  }

  /**
   * Gets the legal last name of the customer.
   *
   * @return the last name
   */
  @Nullable
  public String getLastName() {
    return lastName;
  }

  /**
   * Gets any note data you have associated with the Candidate.
   *
   * @return the stored note
   */
  @Nullable
  public String getNote() {
    return note;
  }

  /**
   * Gets either the 4 digits of the US Social Security Number or the whole SSN.
   *
   * @return the SSN
   */
  @Nullable
  public String getSsn() {
    return socialSecurityNumber;
  }

  /**
   * The passport number of the individual being verified. is only used for verifying non-US customers.
   *
   * @return the passport number
   */
  @Nullable
  public String getPassport() {
    return passport;
  }

  /**
   * The date of birth of your candidate.
   *
   * @return the date of birth
   */
  @Nullable
  public Date getDateOfBirth() {
    if (dateOfBirth == null) {
      return null;
    }
    return new Date(dateOfBirth.getTime());
  }

  /**
   * Gets the primary street address for this person.
   *
   * @return the address
   */
  @Nullable
  public Address getAddress() {
    Address addressObject = new Address(addressStreet1,
                      addressStreet2,
                      addressCity,
                      addressSubdivision,
                      addressPostalCode,
                      addressCountryCode);
    return addressObject;
  }

  /**
   * Sets the internal REST api adapter needed to complete Blockscore API requests.
   *
   * @param restAdapter  the REST adapter
   */
  public void setAdapter(BlockscoreRestAdapter restAdapter) {
    this.restAdapter = restAdapter;
  }

  /**
   * The builder used for constructing a {@link Candidate}.
   */
  public static class Builder {
    private BlockscoreRestAdapter restAdapter;
    private Candidate candidate;

    public Builder(BlockscoreApiClient client) {
      this.restAdapter = client.getAdapter();
      candidate = new Candidate();
    }

     /**
      * Sets the legal first name of the customer.
      *
      * @param firstName the first name
      * @return this
      */
    @NotNull
    public Builder setFirstName(@NotNull final String firstName) {
      candidate.setFirstName(firstName);
      return this;
    }

    /**
     * Sets the legal middle name of the candidate.
     *
     * @param middleName the middle name
     * @return this
     */
    @NotNull
    public Builder setMiddleName(@NotNull final String middleName) {
      candidate.setMiddleName(middleName);
      return this;
    }

    /**
     * Sets the legal last name of the candidate.
     *
     * @param lastName the last name
     * @return this
     */
    @NotNull
    public Builder setLastName(@NotNull final String lastName) {
      candidate.setLastName(lastName);
      return this;
    }

    /**
     * You can store additional information about the candidate here such as your internal system's
     * identifier for this individual. This will allow you to keep track of them.
     *
     * @param note the additional information to store
     * @return this
     */
    @NotNull
    public Builder setNote(@Nullable final String note) {
      candidate.setNote(note);
      return this;
    }

    /**
     * Can be either the last 4 digits of the US Social Security Number or the whole SSN.
     *
     * @param ssn the SSN to use
     * @return this
     */
    @NotNull
    public Builder setSsn(@Nullable final String ssn) {
      candidate.setSsn(ssn);
      return this;
    }

    /**
     * Sets the passport number of the individual being verified. is only used for verifying non-US customers.
     *
     * @param passport the passport data
     * @return this
     */
    @NotNull
    public Builder setPassport(@Nullable final String passport) {
      candidate.setPassport(passport);
      return this;
    }

    /**
     * Set the date of birth of your candidate.
     *
     * @param dateOfBirth  the date of birth
     * @return this
     */
    @NotNull
    public Builder setDateOfBirth(@Nullable final Date dateOfBirth) {
      candidate.setDateOfBirth(dateOfBirth);
      return this;
    }

    /**
     * Sets the primary street address for this person.
     *
     * @param address the address
     * @return this
     */
    public Builder setAddress(@NotNull final Address address) {
      candidate.setAddress(address);
      return this;
    }

    /**
     * Creates a new {@link Candidate}.
     *
     * @return this
     */
    public Candidate create() {
      candidate = restAdapter.createCandidate(candidate);
      candidate.setAdapter(restAdapter);
      return candidate;
    }
  }
}


package com.blockscore.net;

import com.blockscore.common.Constants;
import com.blockscore.models.Candidate;
import com.blockscore.models.Company;
import com.blockscore.models.PaginatedResult;
import com.blockscore.models.Person;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jetbrains.annotations.NotNull;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;
import retrofit.converter.JacksonConverter;

import java.io.UnsupportedEncodingException;

import javax.xml.bind.DatatypeConverter;

/**
 * The Blockscore Java API client.
 */
public class BlockscoreApiClient {
  private static RestAdapter.LogLevel logLevel = RestAdapter.LogLevel.NONE;
  private String apiKey;

  private final BlockscoreRestAdapter restAdapter;

  /**
   * Turns on/off logging. Must be set before creating API client to take effect.
   *
   * @param useVerboseLogs  whether or not to use verbose network logs.
   */
  public static void useVerboseLogs(final boolean useVerboseLogs) {
    if (useVerboseLogs) {
      logLevel = RestAdapter.LogLevel.FULL;
    } else {
      logLevel = RestAdapter.LogLevel.NONE;
    }
  }

  /**
   * Creates a BlockscoreApiClient. Requires a valid API key for construction to occur successfully.
   *
   * @param apiKey  the valid Blockscore API key
   */
  public BlockscoreApiClient(@NotNull final String apiKey) {
    this.apiKey = apiKey + ":";

    RestAdapter.Builder restBuilder = new RestAdapter.Builder().setClient(new BlockscoreHttpClient())
                                                               .setEndpoint(Constants.BLOCKSCORE_DOMAIN);
    restBuilder.setConverter(getDefaultConverter());
    restBuilder.setRequestInterceptor(getDefaultRequestInterceptor());
    restBuilder.setErrorHandler(new BlockscoreErrorHandler());
    restBuilder.setLogLevel(logLevel);

    restAdapter = restBuilder.build().create(BlockscoreRestAdapter.class);
  }

  /**
   * Gets a single person exactly as it was when you created it.
   * This route is useful for auditing purposes as you can provide proof that a verification took place
   * along with all of its associated data.
   *
   * @param id  ID of Person.
   * @return the person, not null
   */
  @NotNull
  public Person retrievePerson(@NotNull final String id) {
    Person person = restAdapter.retrievePerson(id);
    person.setAdapter(restAdapter);
    return person;
  }

  /**
   * Lists a historical record of all verifications that you have completed.
   * The list is displayed in reverse chronological order (newer people appear first).
   *
   * @return the historical listing of created people, not null
   */
  @NotNull
  public PaginatedResult<Person> listPeople() {
    PaginatedResult<Person> result = restAdapter.listPeople();

    for (Person person : result.getData()) {
      person.setAdapter(restAdapter);
    }

    return result;
  }

  /**
   * Gets a single company exactly as it was when you created it.
   * This route is useful for auditing purposes as you can provide proof that a company verification took place
   * along with all of its associated data.
   *
   * @param id  ID of the Company.
   * @return the company, not null
   */
  @NotNull
  public Company retrieveCompany(@NotNull final String id) {
    return restAdapter.retrieveCompany(id);
  }

  /**
   * Lists verified companies a historical record of all company verifications that you have completed.
   * The list is displayed in reverse chronological order (newer company verifications appear first).
   *
   * @return the historical listing of created companies, not null
   */
  @NotNull
  public PaginatedResult<Company> listCompanies() {
    return restAdapter.listCompanies();
  }

  /**
   * Retrieves a candidate.
   *
   * @param id  ID of the candidate.
   * @return the candidate, not null
   */
  @NotNull
  public Candidate retrieveCandidate(@NotNull final String id) {
    Candidate candidate = restAdapter.retrieveCandidate(id);
    candidate.setAdapter(restAdapter);
    return candidate;
  }

  /**
   * Lists a historical record of all candidates you have created.
   * The list is displayed in reverse chronological order (newer candidates appear first).
   *
   * @return the historical listing of created candidates, not null
   */
  @NotNull
  public PaginatedResult<Candidate> listCandidates() {
    PaginatedResult<Candidate> result = restAdapter.listCandidates();

    for (Candidate candidate : result.getData()) {
      candidate.setAdapter(restAdapter);
    }

    return result;
  }

  /**
   * Encodes the API key for Basic authentication.
   *
   * @return the API key with Base 64 encoding
   */
  @NotNull
  private String getEncodedAuthorization() {
    try {
      return "Basic " + DatatypeConverter.printBase64Binary(apiKey.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  private JacksonConverter getDefaultConverter() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibilityChecker(mapper.getSerializationConfig()
                                        .getDefaultVisibilityChecker()
                                        .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                                        .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                                        .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                                        .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
    return new JacksonConverter(mapper);
  }

  private RequestInterceptor getDefaultRequestInterceptor() {
    return new RequestInterceptor() {
      @Override
      public void intercept(RequestFacade request) {
        request.addHeader(Constants.AUTHORIZATION_HEADER, getEncodedAuthorization());
        request.addHeader(Constants.ACCEPT_HEADER, Constants.getAcceptHeaders());
      }
    };
  }

  /**
   * Gets the internal REST api adapter needed to complete Blockscore API requests.
   *
   * @return the REST adapter
   */
  public BlockscoreRestAdapter getAdapter() {
    return restAdapter;
  }
}


package com.blockscore.models;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Date;
import java.util.GregorianCalendar;

/**
 * The model representing a date of birth interval. The end of the range may be empty.
 */
public class BirthRange {
  @NotNull
  @JsonProperty("birth_day")
  private Integer birthDay;

  @NotNull
  @JsonProperty("birth_month")
  private Integer birthMonth;

  @NotNull
  @JsonProperty("birth_year")
  private Integer birthYear;

  @Nullable
  @JsonProperty("birth_day_end")
  private Integer birthDayEnd;

  @Nullable
  @JsonProperty("birth_month_end")
  private Integer birthMonthEnd;

  @Nullable
  @JsonProperty("birth_year_end")
  private Integer birthYearEnd;

  /**
   * Returns the start of the date of birth range.
   *
   * @return the start of the date of birth range
   */
  @NotNull
  public Date getDateOfBirth() {
    GregorianCalendar calendar = new GregorianCalendar(birthYear, birthMonth, birthDay);
    return calendar.getTime();
  }

  /**
   * Returns the end of the date of birth range.
   *
   * @return the end of the date of birth range, may be null
   */
  @Nullable
  public Date getDateOfBirthEnd() {
    if (birthDayEnd == null || birthMonthEnd == null || birthYearEnd == null) {
      return null;
    }

    GregorianCalendar calendar = new GregorianCalendar(birthYearEnd, birthMonthEnd, birthDayEnd);
    return calendar.getTime();
  }
}


package com.buschmais.jqassistant.plugin.common.api.scanner;

import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

import com.buschmais.jqassistant.core.scanner.api.ScannerContext;
import com.buschmais.jqassistant.core.scanner.api.ScannerPlugin;
import com.buschmais.jqassistant.core.store.api.model.Descriptor;

/**
 * Abstract base implementation of a {@link ScannerPlugin}.
 */
public abstract class AbstractScannerPlugin<I, D extends Descriptor> implements ScannerPlugin<I, D> {

    private Map<String, Object> properties;

    private ScannerContext scannerContext;

    @Override
    public final void configure(ScannerContext scannerContext, Map<String, Object> properties) {
        this.scannerContext = scannerContext;
        this.properties = properties;
        configure();
    }

    /**
     * Convenience method which might be overridden by sub-classes.
     */
    protected void configure() {
    }

    @Override
    public Class<? extends I> getType() {
        return getTypeParameter(AbstractScannerPlugin.class, 0);
    }

    @Override
    public Class<D> getDescriptorType() {
        return getTypeParameter(AbstractScannerPlugin.class, 1);
    }

    @Override
    public String getName() {
        return getClass().getSimpleName();
    }

    /**
     * Determines the type parameter for a generic super class.
     *
     * @param expectedSuperClass
     *            The generic super class.
     * @param genericTypeParameterIndex
     *            The index, e.g. 0 for the first.
     * @return The type parameter.
     */
    protected <T> Class<T> getTypeParameter(Class<?> expectedSuperClass, int genericTypeParameterIndex) {
        Class<? extends AbstractScannerPlugin> thisClass = this.getClass();
        if (!thisClass.getSuperclass().equals(expectedSuperClass)) {
            throw new IllegalStateException("Cannot determine type argument of " + thisClass.getName());
        }
        Type genericSuperclass = thisClass.getGenericSuperclass();
        Type typeParameter = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[genericTypeParameterIndex];
        if (typeParameter instanceof ParameterizedType) {
            return (Class<T>) ((ParameterizedType) typeParameter).getRawType();
        }
        return (Class<T>) typeParameter;
    }

    /**
     * Get all properties.
     *
     * @return The properties.
     */
    protected Map<String, Object> getProperties() {
        return properties;
    }

    /**
     * Get the value of a property.
     *
     * @param name
     *            The name of the property.
     * @param type
     *            The expected type.
     * @param <T>
     *            The type.
     * @return The value.
     */
    protected <T> T getProperty(String name, Class<T> type) {
        return type.cast(properties.get(name));
    }

    /**
     * Get a property as string.
     *
     * @param name
     *            The name.
     * @param defaultValue
     *            The default value.
     * @return The value.
     */
    protected String getStringProperty(String name, String defaultValue) {
        Object value = properties.get(name);
        return value != null ? value.toString() : defaultValue;
    }

    /**
     * Get a property as boolean.
     *
     * @param name
     *            The name.
     * @param defaultValue
     *            The default value.
     * @return The value.
     */
    protected Boolean getBooleanProperty(String name, Boolean defaultValue) {
        Object value = properties.get(name);
        return value != null ? Boolean.valueOf(value.toString()) : defaultValue;
    }

    /**
     * Return the scanner context.
     *
     * @return The scanner context.
     */
    protected ScannerContext getScannerContext() {
        return scannerContext;
    }

    /**
     * Return the relative path of a file within a directory.
     *
     * @param directory
     *            The directory.
     * @param entry
     *            The file.
     * @return The relative path.
     */
    protected String getDirectoryPath(File directory, File entry) {
        String relativePath;
        if (entry.equals(directory)) {
            relativePath = "/";
        } else {
            String filePath = entry.getAbsolutePath();
            String directoryPath = directory.getAbsolutePath();
            relativePath = filePath.substring(directoryPath.length()).replace(File.separator, "/");
        }
        return relativePath;
    }

    @Override
    public final boolean equals(Object obj) {
        return super.equals(obj);
    }

    @Override
    public final int hashCode() {
        return super.hashCode();
    }
}


package com.blockscore.models.error;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * Request Error model.
 */
public class RequestError {
  @Nullable
  @JsonProperty("param")
  private String param;

  @Nullable
  @JsonProperty("message")
  private String message;

  @Nullable
  @JsonProperty("type")
  private String type;

  @Nullable
  @JsonProperty("code")
  private String code;

  /**
   * Gets the invalid parameter.
   * @return the invalid parameter
   */
  @Nullable
  public String getParam() {
    return param;
  }

  /**
   * Gets the error message.
   * @return the error message
   */
  @Nullable
  public String getMessage() {
    return message;
  }

  /**
   * Gets the error type.
   * @return the error type
   */
  @NotNull
  public BlockscoreErrorType getErrorType() {
    if (type == null) {
      return BlockscoreErrorType.UNKNOWN;
    } else {
      return BlockscoreErrorType.toEnum(type);
    }
  }

  /**
   * Gets the validation error type.
   *
   * @return the validation error type
   */
  @NotNull
  public ValidationErrorType getValidationErrorCode() {
    if (code == null) {
      return ValidationErrorType.UNKNOWN;
    } else {
      return ValidationErrorType.toEnum(code);
    }
  }
}