@Override
  public Object run(ExtratoAnalyseSwitches switches) throws ExtratoAnalyseException {
    checkParamValid(switches);

    manualRefList = makeManualRefList(switches);

    banco = getConta(switches.getNomeBanco());

    List<Lancamento> lancamentoSemExtratoList = getLancamentoSemExtratoList();

    List<ExtratoLancamento> extratoLancamentoOrfao = getExtratoLancamentoOrfao(banco);

    if (extratoLancamentoOrfao.size() == 0) {
      System.out.println();
      System.out.println(
          "Nenhum item de extrato órfão encontrado para o banco \"" + banco.getNome() + "\".");

      return null;
    }

    TextGrid grid = createGrid();
    List<ExtratoLineAnalyseResult> statuses;

    try {
      statuses = makeSync(lancamentoSemExtratoList, extratoLancamentoOrfao, switches);
    } catch (ExtratoLineParserException e) {
      throw new ExtratoAnalyseException(e);
    }

    grid.setValues(statuses);

    try {
      grid.show();
    } catch (TextGridException e) {
      throw new ExtratoAnalyseException(e);
    }

    System.out.println();
    System.out.println("Legenda:");
    System.out.println("  - : Não se aplica.");
    System.out.println("  U : Update.");
    System.out.println("  * : Insert.");
    System.out.println("  X : Delete.");
    System.out.println("  ! : Conta não encontrada.");

    return null;
  }
  private List<InternalManualReference> makeManualRefList(ExtratoAnalyseSwitches switches)
      throws ExtratoAnalyseException {
    List<InternalManualReference> mrl = new ArrayList<InternalManualReference>();

    ContaDAO dao = new ContaDAO();

    for (ManualReference mr : switches.getManualRefList()) {
      InternalManualReference imr = new InternalManualReference();

      Conta conta = dao.getByNome(mr.getNomeConta());

      if (conta == null) {
        throw new ExtratoAnalyseException(
            "Referências manuais: conta " + mr.getNomeConta() + "não encontrada.");
      }

      imr.setConta(conta);
      imr.setRegex(mr.getRegex());

      mrl.add(imr);
    }

    return mrl;
  }
 private void checkParamValid(ExtratoAnalyseSwitches switches) throws ExtratoAnalyseException {
   if (switches.getNomeBanco() == null) {
     throw new ExtratoAnalyseException("Nome do banco deve ser informado.");
   }
 }
  private ExtratoLineAnalyseResult syncTransactionLine(
      List<Lancamento> lancamentoSemExtratoList,
      ContaDAO contaDAO,
      ExtratoLancamentoTransaction line,
      ExtratoAnalyseSwitches switches) {
    ExtratoLineAnalyseResult result = new ExtratoLineAnalyseResult();
    result.setLinhaStatus(StatusLinha.TRANSACTION);

    Conta contaExtrato = resolveReference(contaDAO, line.getReferencia());

    if (contaExtrato == null) {
      result.setLancamentoStatus(LancamentoStatus.CONTA_NOT_FOUND);
      return result;
    }

    TimeIgnoringComparator comparator = new TimeIgnoringComparator();

    for (Lancamento lancamentoSemExtrato : lancamentoSemExtratoList) {
      // Ignora as linhas anteriores ao lancamento sem extrato
      int comparision = comparator.compare(lancamentoSemExtrato.getData(), line.getData());

      if (comparision < 0) {
        continue;
      } else if (comparision > 0) {
        // Se passou da data, sai do loop, não há correspondência
        break;
      }

      Conta contaOrigemEsperada;
      Conta contaDestinoEsperada;

      if (line.getValor() < 0) {
        // Dinheiro saiu da conta
        contaOrigemEsperada = banco;
        contaDestinoEsperada = contaExtrato;
      } else {
        // Dinheiro entrou na conta
        contaOrigemEsperada = contaExtrato;
        contaDestinoEsperada = banco;
      }

      if ((lancamentoSemExtrato.getExtrato() == null)
          && (extratoLineMatch(
              lancamentoSemExtrato, line, contaOrigemEsperada, contaDestinoEsperada))) {
        result.setLancamentoStatus(LancamentoStatus.UPDATE);

        lancamentoSemExtrato.setExtrato(line.getOrigem());

        if (switches.getRealize()) {
          lancamentoDAO.alterar(lancamentoSemExtrato);
        }

        result.setLancamento(lancamentoSemExtrato);

        return result;
      }
    }

    // Nenhum lançamento correspondente encontrado
    result.setLancamentoStatus(LancamentoStatus.NEW);

    Lancamento novoLancamento = new Lancamento();

    result.setLancamento(novoLancamento);

    novoLancamento.setData(line.getData());

    int n = (switches.getRealize() ? lancamentoDAO.getNextN(line.getData()) : -1);
    novoLancamento.setN(n);

    Conta contaOrigemEsperada;
    Conta contaDestinoEsperada;

    if (line.getValor() > 0) {
      // Dinheiro entrou da conta
      contaOrigemEsperada = contaExtrato;
      contaDestinoEsperada = banco;
    } else {
      // Dinheiro saiu na conta
      contaOrigemEsperada = banco;
      contaDestinoEsperada = contaExtrato;
    }

    novoLancamento.setContaOrigem(contaOrigemEsperada);
    novoLancamento.setContaDestino(contaDestinoEsperada);

    novoLancamento.setValor(Math.abs(line.getValor()));

    novoLancamento.setExtrato(line.getOrigem());

    if (switches.getRealize()) {
      lancamentoDAO.inserir(novoLancamento);
    }

    return result;
  }