public class OracleCrawler extends AbstractDisCrawler {
    /**
     * Crawler database name.
     */
    public static final String CRAWLER_DATABASE_NAME = "oracle";
    /**
     * Crawler name.
     */
    private static final String CRAWLER_NAME = "OracleDisCrawlerTest";
    /**
     * Crawler start properties.
     */
    private final Map<String, Object> startProperties = new HashMap<>();

    /**
     * Constructor.
     */
    public OracleCrawler() {
        super();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Nonnull
    protected Map<String, Object> getStartProperties() {
        return this.startProperties;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Nonnull
    protected String getCrawlerUrlSegment() {
        return CRAWLER_DATABASE_NAME;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Nonnull
    public CrawlerDescriptor descriptor() {

        CrawlerDescriptor crawlerDescriptor = new CrawlerDescriptor();
        crawlerDescriptor.setName(CRAWLER_NAME);
        crawlerDescriptor.setDisplayName(() -> "Тестовый краулер Oracle");
        crawlerDescriptor.setDescription(() -> "Описание краулера");
        crawlerDescriptor.setConnectParameters(OracleDisCrawlerParameters.getOracleParameters());
        crawlerDescriptor.setSupported(Collections.singletonList(CrawlerExecutionScope.META));

        return crawlerDescriptor;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void configure(CrawlerConfiguration configuration) {
        super.configure(configuration);

        CrawlerParameters connectParameters = configuration.getConnectParameters();

        OracleDisCrawlerParameters.getOracleParameters().stream()
                .map(param -> Pair.of(param.getName(), connectParameters.getSingle(param.getName())))
                .forEach(param -> startProperties.put(
                        param.getKey(),
                        Objects.isNull(param.getValue()) ? StringUtils.EMPTY : param.getValue())
                );

        this.startProperties.put("oracleScannerAgentOption", "");
        this.startProperties.put("oracleScannerTrackSourceChanges", false);
        this.startProperties.put("resourceTypeId", "Oracle");
        this.startProperties.put("oracleScannerScannerExecutionMode", "offline");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Nullable
    protected byte[] getXmlModel() {
        try {
            return StreamUtils.copyToByteArray((new ClassPathResource("relational_dg_model.xml")).getInputStream());
        } catch (IOException e) {
            return new byte[0];
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Nonnull
    protected Map<Pair<String, DisCrawlerElementType>, String> getModelNameCollisions() {

        Map<Pair<String, DisCrawlerElementType>, String> collisions = new HashMap<>();
        Pair<String, DisCrawlerElementType> viewColumn = Pair.of("com_infa_ldm_relational_ViewColumn", DisCrawlerElementType.RELATION);
        collisions.put(viewColumn, "com_infa_ldm_relational_ViewColumnViewColumn");

        return collisions;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<String> topLevelAssetTypeNames() {
        return List.of("com_infa_ldm_relational_Database", "com_infa_ldm_relational_HiveModel");
    }
}