#pragma once

#ifndef _HOST_ID_PARTITION_UTIL_H_INCLUDED_
#define _HOST_ID_PARTITION_UTIL_H_INCLUDED_

#include <string>
#include <sstream>
#include <iomanip>
#include <map>
#include <cctype>

class HostIdPartitionUtil {
public:

    static HostIdPartitionUtil *instance();
    std::string partitionedSQL(const std::string &sql, long long hostId);

    class Iterator {
    public:
        Iterator(long from);

        bool next();
        std::string partitionedSQL(const std::string &sql);
        long current() {
            return fCurrent;
        }

    private:
        long fStartFrom;
        long fCurrent;
    };

    static const int numberOfPartitions = 512;

    inline static int getPartition(long long hostId) {
        return getPartition(hostId, numberOfPartitions);
    }

    inline static int getPartition(long long hostId, int numOfParts) {
        return hostId % numOfParts;
    }

private:

    /**
     * See as: <code>
    $ hdb1 --silent -e "show tables" | sed -e 's/[0-9]//g' | uniq -c | grep -v -E '^ *1 '
     512 tbl_code_error_trees
     512 tbl_custom_queries
     512 tbl_customquery_history
     512 tbl_error_urls
     512 tbl_host_daily_state
     512 tbl_queries
     512 tbl_query_stats
     512 tbl_sitemap_errors
     512 tbl_sitemap_parse_errors
     512 tbl_sitemaps
     512 tbl_topclicks_queries
     512 tbl_topshows_queries
     512 tbl_total_queries_stats
     512 tbl_url_trees
     * </code>
     * Generate as <code>
    $hdb0 --silent -e "show tables" | sed -e 's/[0-9]//g' | uniq -c | grep -v -E '^ *1 ' | awk '{print "\tpartitions[\""$2"\"] = "$1";" }'
     * </code>
     */
    HostIdPartitionUtil() {
//      partitions["tbl_code_error_trees"] = 512;
        partitions["tbl_code_agr_error_trees"] = 512;
        partitions["tbl_custom_queries"] = 512;
        partitions["tbl_custom_regions"] = 512;
        partitions["tbl_customquery_history"] = 512;
        partitions["tbl_error_urls"] = 512;
        partitions["tbl_host_daily_state"] = 512;
        partitions["tbl_queries"] = 512;
        partitions["tbl_query_stats"] = 512;
        partitions["tbl_sitemap_errors"] = 512;
        partitions["tbl_sitemap_parse_errors"] = 512;
        partitions["tbl_sitemaps"] = 512;
//      partitions["tbl_topclicks_queries"] = 512;
//      partitions["tbl_topshows_queries"] = 512;
        partitions["tbl_total_queries_stats"] = 512;
        partitions["tbl_url_trees"] = 512;
        partitions["tbl_code_error_sitemap"] = 512;
        partitions["tbl_error_urls_sitemaps"] = 512;
        partitions["tbl_sitemap_cur_errors"] = 512;
        partitions["tbl_sitemap_cur_parse_errors"] = 512;
        partitions["tbl_sitemaps_cur"] = 512;
        partitions["tbl_hostmon_stats"] = 512;
        partitions["tbl_host_total_errors"] = 512;
        partitions["tbl_trend_robotdb_info_urls"] = 512;
        partitions["tbl_trend_url_trees_urls"] = 512;
        partitions["tbl_trend_robotdb_info_index_count"] = 512;
        partitions["tbl_trend_url_trees_index_count"] = 512;
        partitions["tbl_trend_tcy"] = 512;
        partitions["tbl_trend_links_count"] = 512;
        partitions["tbl_trend_code_error_trees_count"] = 512;
        partitions["tbl_all_about_url_results"] = 512;
        partitions["tbl_all_about_url_prod"] = 512;
        partitions["tbl_all_about_url_cur"] = 512;
        partitions["tbl_all_about_url_htarc"] = 512;
        partitions["tbl_all_about_url_canonical"] = 512;
        partitions["tbl_sitemaps_indexes_cur"] = 512;
        partitions["tbl_sitemaps_indexes"] = 512;
    }

    static std::map<std::string, int> partitions;

    inline bool isNameChar(char ch) {
        // NB: MySQL supports very complex names in any charset.
        // It is difficult to check all possible cases here,
        // so we introduce constraints for names which could be partitioned:
        // name MUST include only a-z, A-Z, 0-9 and _ symbols
        return std::isalnum(ch) || ch == '_';
    }

    void replaceName(std::string &sql, const std::string &name, int n);
};

#define HOST_ID_PARTITION(result, hostId, message) \
    do { \
        std::ostringstream os; \
        os << message; \
        result = HostIdPartitionUtil::instance()->partitionedSQL(os.str(), hostId); \
    } while (0)



#endif // _HOST_ID_PARTITION_UTIL_H_INCLUDED_
