class ChefCookbookAnalyzer {

    public CookbookParseResult compileCookbook(CookbookParseResult cookbookParseResult, boolean saveToToscaRepo) {
        
        CookbookParseResult oldParseResult = new CookbookParseResult(cookbookParseResult);
        List<CrawlCookbookRunnable> crawlCookbookRunnableList = new ArrayList<>();
        
        //Compile metadata.
        cookbookParseResult = returnComponentTypesFromMetadata(cookbookParseResult);

        // cookbookParseResult is null when cookbook has no metadata.rb or metadata.json file.
        if ( cookbookParseResult == null) {
            return oldParseResult;
        }

        //Crawl dependent cookbooks in threads.
        if (cookbookParseResult.getAllConfigsAsList().size() > 0) {
            LinkedHashMap<String,String> dependencies = cookbookParseResult.getAllConfigsAsList().get(0).getDepends();
            String pathDependencies = cookbookParseResult.getCookbookPath() + Defaults.DEPENDENCIE_FOLDER;
            for (String key : dependencies.keySet()) {
                String versionRestriciton = dependencies.get(key);
                CrawlCookbookRunnable crawlDependency = new CrawlCookbookRunnable(key, versionRestriciton, pathDependencies, Defaults.TEMP_FOLDER_PATH);
                crawlDependency.start();
                crawlCookbookRunnableList.add(crawlDependency);
            }
        }

        // Compile kitchen.yml
        if (cookbookParseResult.isInRecursiveTransformation() == false ) {
            cookbookParseResult = addPlatformVersionInformationFromKitchen(cookbookParseResult);
        }

        // Wait for the dependencies to download.
        for (int i = 0; i < crawlCookbookRunnableList.size(); i++) {
            try {
                crawlCookbookRunnableList.get(i).join();
            } catch (InterruptedException e) {
                LOGGER.info("Crawling process of dependent cookbook " + crawlCookbookRunnableList.get(i).getThreadName() + " interrupted");
            }
        }

        // Compile attribute files.
        cookbookParseResult = returnComponentTypesFromAttributes(cookbookParseResult);

        // Compile recipes, starting from default.rb recipe.
        cookbookParseResult = returnComponentTypesFromRecipes(cookbookParseResult);

        // Resolve dependencies
        for (Map.Entry<String,String> entry : cookbookParseResult.getAllConfigsAsList().get(0).getDepends().entrySet()) {
            String key = entry.getKey();
            LOGGER.info("Cookbook: " + key + " is resolved now");
            CookbookParseResult dependentParseResult = new CookbookParseResult(cookbookParseResult);
            dependentParseResult.prepareForDependencie(key);
            if (dependentParseResult.getAllConfigsAsList().size() > 0) {
                compileCookbook(dependentParseResult, saveToToscaRepo);
            }
        }

        // Print information about cookbooks for debugging
        List<ChefCookbookConfiguration> cookbookConfigsList = cookbookParseResult.getAllConfigsAsList();
        for (int count = 0; count < cookbookConfigsList.size(); count++) {
            cookbookConfigsList.get(count).printConfiguration();
        }

        /**
         * Convert extacted configuations to TOSCA node types.
         * Extracted platforms are also converted to TOSCA node types.
         * Saves the extracted Node types to repository.
         */
        if (saveToToscaRepo) {
            new ParseResultToscaConverter().saveToscaNodeTypes(new ParseResultToscaConverter().convertCookbookConfigurationToToscaNode(cookbookParseResult));
        }
        
        LOGGER.info("Finished parsing");
        return cookbookParseResult;
    }

}