/*
 *
 * UGGeoHash.cpp
 *
 * Copyright (C) 2021-2024 SuperMap Software Co., Ltd.
 *
 * Yukon is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; If not, see <http://www.gnu.org/licenses/>. *
 */

#include "UGGeoHash.h"

namespace Yk
{

    UGGeoHash::UGGeoHash()
    {
    }

    UGGeoHash::~UGGeoHash()
    {
    }

    YkInt UGGeoHash::ComputerGeoHash(YkRect2D IndexBounds, YkArray<YkLong> &AryKeys, YkRect2D GeoBounds,
                                     YkInt nUpperLimitLevel, YkInt nMaxReturnKeyCount)
    {
        if (!IndexBounds.Contains(GeoBounds))
        {
            AryKeys.Add(-1);
            return -1;
        }

        //传入的geobounds接近indexbound情况;
        YkRect2D rcTemp(IndexBounds);
        rcTemp.IntersectRect(GeoBounds);

        YkArray<QueryParameter> aryResult;
        aryResult.SetGrowSize(nMaxReturnKeyCount + 4);

        QueryParameter qFirst;
        qFirst.lGeoKey = 0;
        qFirst.nLevel = 0;
        qFirst.rcGeoKey = IndexBounds;
        qFirst.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / IndexBounds.Width() / IndexBounds.Height();
        qFirst.rcQueryBounds = rcTemp;

        aryResult.Add(qFirst);

        YkArray<QueryParameter> aryGeoKeys;
        while ((YkInt)aryResult.GetSize() < nMaxReturnKeyCount)
        {
            aryGeoKeys.RemoveAll();
            YkInt n = GetMinPercentagePos(aryResult);
            if (aryResult[n].dPercentage < PERCENTAGE)
            {
                UGGeoHash::GetIntersectHash(aryResult[n], aryGeoKeys);
                aryResult.RemoveAt(n);
            }
            else
            {
                break;
            }

            YkBool bBreak = FALSE;
            for (YkUint i = 0; i < aryGeoKeys.GetSize(); i++)
            {
                if (aryGeoKeys[i].nLevel >= nUpperLimitLevel)
                {
                    bBreak = TRUE;
                }
                aryResult.Add(aryGeoKeys[i]);
            }

            if (bBreak)
            {
                break;
            }
        }

        for (YkInt i = aryResult.GetSize() - 1; i >= 0; i--)
        {
            YkLong lGeoKey = aryResult[i].lGeoKey;
            lGeoKey <<= (64 - aryResult[i].nLevel * 2 - 2);
            lGeoKey += aryResult[i].nLevel;
            AryKeys.Add(lGeoKey);
        }
        return 0;
    }

    YkInt UGGeoHash::ComputerGeoHash2(YkRect2D IndexBounds, YkArray<YkLong> &AryKeys, YkRect2D GeoBounds, YkInt nUpperLimitLevel, YkInt nMaxReturnKeyCount)
    {
        //找到level
        //确定4个还是1个

        YkInt nLevel = 0;
        YkDouble dWidth = GeoBounds.Width();
        YkDouble dHeight = GeoBounds.Height();
        YkDouble dIndexWidth = IndexBounds.Width();
        YkDouble dIndexHeight = IndexBounds.Height();
        if (dWidth / dHeight > dIndexWidth / dIndexHeight)
        {
            YkDouble dTemp = dIndexWidth;
            for (YkInt i = 0; i < MAXHASHLEVEL; i++)
            {
                if (dWidth >= dTemp)
                {
                    nLevel = i;
                    break;
                }
                dTemp /= 2;
            }
        }
        else
        {
            YkDouble dTemp = dIndexHeight;
            for (YkInt i = 0; i < MAXHASHLEVEL; i++)
            {
                if (dHeight >= dTemp)
                {
                    nLevel = i;
                    break;
                }
                dTemp /= 2;
            }
        }
        YkLong nHashKey;
        YkPoint2D pnt;
        pnt.x = GeoBounds.left;
        pnt.y = GeoBounds.bottom;
        ComputerPointGeoHash(IndexBounds, nHashKey, pnt, nLevel);
        AryKeys.Add(nHashKey);

        pnt.x = GeoBounds.left;
        pnt.y = GeoBounds.top;
        ComputerPointGeoHash(IndexBounds, nHashKey, pnt, nLevel);

        YkBool bFind = FALSE;
        for (YkUint i = 0; i < AryKeys.GetSize(); i++)
        {
            if (nHashKey == AryKeys[i])
            {
                bFind = TRUE;
                break;
            }
        }
        if (!bFind)
        {
            AryKeys.Add(nHashKey);
        }

        pnt.x = GeoBounds.right;
        pnt.y = GeoBounds.bottom;
        ComputerPointGeoHash(IndexBounds, nHashKey, pnt, nLevel);

        bFind = FALSE;
        for (YkUint i = 0; i < AryKeys.GetSize(); i++)
        {
            if (nHashKey == AryKeys[i])
            {
                bFind = TRUE;
                break;
            }
        }
        if (!bFind)
        {
            AryKeys.Add(nHashKey);
        }

        pnt.x = GeoBounds.right;
        pnt.y = GeoBounds.top;
        ComputerPointGeoHash(IndexBounds, nHashKey, pnt, nLevel);
        bFind = FALSE;
        for (YkUint i = 0; i < AryKeys.GetSize(); i++)
        {
            if (nHashKey == AryKeys[i])
            {
                bFind = TRUE;
                break;
            }
        }
        if (!bFind)
        {
            AryKeys.Add(nHashKey);
        }

        return 0;
    }

    YkInt UGGeoHash::ComputerPointGeoHash(YkRect2D IndexBounds, YkLong &GeoHashKey, YkPoint2D pnt, YkInt nUpperLimitLevel)
    {
        YkDouble dxStep = IndexBounds.Width() / pow(2, nUpperLimitLevel);
        YkDouble dyStep = IndexBounds.Height() / pow(2, nUpperLimitLevel);

        if (pnt.x >= IndexBounds.right)
        {
            pnt.x -= EP;
        }

        if (pnt.y >= IndexBounds.top)
        {
            pnt.y -= EP;
        }

        YkLong lXPos = YKFLOOR((pnt.x - IndexBounds.left) / dxStep);
        YkLong lYPos = YKFLOOR((pnt.y - IndexBounds.bottom) / dyStep);

        GeoHashKey = 0;
        YkLong lnTemp = 0;
        for (YkInt n = nUpperLimitLevel; n > 0; n--)
        {
            YkInt lxlast = lXPos % 2;
            YkInt lylast = lYPos % 2;
            lnTemp = lxlast * 2 + lylast;
            GeoHashKey |= lnTemp << (64 - n * 2 - 2);
            lXPos /= 2;
            lYPos /= 2;
        }
        GeoHashKey += nUpperLimitLevel;
        return 0;
    }

    YkString UGGeoHash::GetFilter2(YkRect2D IndexBounds, YkRect2D GeoBounds, YkInt nUpperLimitLevel)
    {
        if (!UGGeoHash::IsIntersect(IndexBounds, GeoBounds))
        {
            return _U("");
        }

        YkRect2D rcTemp(IndexBounds);
        rcTemp.IntersectRect(GeoBounds);
        QueryParameter qFirst;
        qFirst.lGeoKey = 0;
        qFirst.nLevel = 0;
        qFirst.rcGeoKey = IndexBounds;
        qFirst.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / IndexBounds.Width() / IndexBounds.Height();
        qFirst.rcQueryBounds = rcTemp;

        YkString strFilter;
        YkArray<QueryParameter> aryEquelKeys;
        aryEquelKeys.SetGrowSize(32);
        YkArray<QueryParameter> aryBetweenKeys;
        aryBetweenKeys.SetGrowSize(32);
        aryBetweenKeys.Add(qFirst);

        while (TRUE)
        {
            YkInt n = GetMinPercentagePos(aryBetweenKeys);
            aryEquelKeys.Add(aryBetweenKeys[n]);
            if (aryBetweenKeys[n].dPercentage < PERCENTAGE)
            {
                UGGeoHash::Query(aryBetweenKeys[n], aryEquelKeys, aryBetweenKeys);
                aryBetweenKeys.RemoveAt(n);
            }
            else
            {
                break;
            }

            if (aryEquelKeys.GetSize() + aryBetweenKeys.GetSize() > 30)
            {
                break;
            }
        }

        YkString strTemp;
        for (YkUint i = 0; i < aryEquelKeys.GetSize(); i++)
        {
            YkLong lGeoKey = aryEquelKeys[i].lGeoKey;
            lGeoKey <<= (64 - aryEquelKeys[i].nLevel * 2 - 2);
            lGeoKey += aryEquelKeys[i].nLevel;
            strTemp.Format(_U(" ht.SmGeoHashKey = %lld "), lGeoKey);
            strFilter += strTemp + _U(" or ");
        }

        for (YkUint i = 0; i < aryBetweenKeys.GetSize(); i++)
        {
            YkLong lGeoKey = aryBetweenKeys[i].lGeoKey;
            lGeoKey <<= (64 - aryBetweenKeys[i].nLevel * 2 - 2);
            lGeoKey += aryBetweenKeys[i].nLevel;
            strTemp = GetBetweenFilter2(lGeoKey);
            strFilter += strTemp + _U(" or ");
        }
        strFilter = strFilter.TrimRightString(_U("or "));
        return strFilter;
    }

    YkString UGGeoHash::GetFilter1(YkRect2D IndexBounds, YkRect2D GeoBounds, YkInt nUpperLimitLevel,YkInt nKeySizeLimit)
    {
        if (!UGGeoHash::IsIntersect(IndexBounds, GeoBounds))
        {
            return _U("");
        }

        YkRect2D rcTemp(IndexBounds);
        rcTemp.IntersectRect(GeoBounds);
        QueryParameter qFirst;
        qFirst.lGeoKey = 0;
        qFirst.nLevel = 0;
        qFirst.rcGeoKey = IndexBounds;
        qFirst.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / IndexBounds.Width() / IndexBounds.Height();
        qFirst.rcQueryBounds = rcTemp;

        YkString strFilter;
        YkArray<QueryParameter> aryEquelKeys;
        aryEquelKeys.SetGrowSize(32);
        YkArray<QueryParameter> aryBetweenKeys;
        aryBetweenKeys.SetGrowSize(32);
        aryBetweenKeys.Add(qFirst);

        while (TRUE)
        {
            // 这里修改为查询权重最小的下标 
            //YkInt n = GetMinPercentagePos(aryBetweenKeys);
            YkInt n = FindLowLevelAndLowPercentage(aryBetweenKeys);
			if (n == -1)
			{
				break;
			}
            aryEquelKeys.Add(aryBetweenKeys[n]);
            if (aryBetweenKeys[n].dPercentage < PERCENTAGE)
            {
                UGGeoHash::Query(aryBetweenKeys[n], aryEquelKeys, aryBetweenKeys);
                aryBetweenKeys.RemoveAt(n);
            }
            else
            {
                break;
            }

            if (aryBetweenKeys.GetSize() > nKeySizeLimit ||
                aryBetweenKeys[aryBetweenKeys.GetSize() - 1].nLevel > nUpperLimitLevel)
            {
                break;
            }
        }

        YkString strTemp;
        for (YkUint i = 0; i < aryBetweenKeys.GetSize(); i++)
        {
            YkLong lGeoKey = aryBetweenKeys[i].lGeoKey;
            lGeoKey <<= (64 - aryBetweenKeys[i].nLevel * 2 - 2);
            lGeoKey += aryBetweenKeys[i].nLevel;
            strTemp = GetBetweenFilter1(lGeoKey);
            strFilter += strTemp + _U(" or ");
        }
        strFilter = strFilter.TrimRightString(_U("or "));
        return strFilter;
    }

    YkBool UGGeoHash::GetIntersectHash(QueryParameter &QueryFetch, YkArray<QueryParameter> &aryRest)
    {
        if (QueryFetch.dPercentage >= 100)
        {
            return TRUE;
        }

        YkDouble dCentX = (QueryFetch.rcGeoKey.left + QueryFetch.rcGeoKey.right) / 2.0;
        YkDouble dCentY = (QueryFetch.rcGeoKey.top + QueryFetch.rcGeoKey.bottom) / 2.0;

        YkRect2D rcTemp;
        rcTemp.left = QueryFetch.rcGeoKey.left;
        rcTemp.bottom = QueryFetch.rcGeoKey.bottom;
        rcTemp.right = dCentX;
        rcTemp.top = dCentY;

        if (UGGeoHash::IsIntersect(QueryFetch.rcQueryBounds, rcTemp))
        {
            QueryParameter query;
            query.lGeoKey = QueryFetch.lGeoKey;
            query.lGeoKey <<= 2;

            query.nLevel = QueryFetch.nLevel + 1;

            query.rcGeoKey = rcTemp;
            rcTemp.IntersectRect(QueryFetch.rcQueryBounds);
            query.rcQueryBounds = rcTemp;
            query.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / query.rcGeoKey.Width() / query.rcGeoKey.Height();
            aryRest.Add(query);
        }

        rcTemp.left = dCentX;
        rcTemp.bottom = QueryFetch.rcGeoKey.bottom;
        rcTemp.right = QueryFetch.rcGeoKey.right;
        rcTemp.top = dCentY;
        if (UGGeoHash::IsIntersect(QueryFetch.rcQueryBounds, rcTemp))
        {
            QueryParameter query;
            query.lGeoKey = QueryFetch.lGeoKey;
            query.lGeoKey <<= 1;
            query.lGeoKey += 1;
            query.lGeoKey <<= 1;

            query.nLevel = QueryFetch.nLevel + 1;

            query.rcGeoKey = rcTemp;
            rcTemp.IntersectRect(QueryFetch.rcQueryBounds);
            query.rcQueryBounds = rcTemp;
            query.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / query.rcGeoKey.Width() / query.rcGeoKey.Height();
            aryRest.Add(query);
        }

        rcTemp.left = QueryFetch.rcGeoKey.left;
        rcTemp.bottom = dCentY;
        rcTemp.right = dCentX;
        rcTemp.top = QueryFetch.rcGeoKey.top;
        if (UGGeoHash::IsIntersect(QueryFetch.rcQueryBounds, rcTemp))
        {
            QueryParameter query;
            query.lGeoKey = QueryFetch.lGeoKey;
            query.lGeoKey <<= 1;
            query.lGeoKey <<= 1;
            query.lGeoKey += 1;

            query.nLevel = QueryFetch.nLevel + 1;

            query.rcGeoKey = rcTemp;
            rcTemp.IntersectRect(QueryFetch.rcQueryBounds);
            query.rcQueryBounds = rcTemp;
            query.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / query.rcGeoKey.Width() / query.rcGeoKey.Height();
            aryRest.Add(query);
        }

        rcTemp.left = dCentX;
        rcTemp.bottom = dCentY;
        rcTemp.right = QueryFetch.rcGeoKey.right;
        rcTemp.top = QueryFetch.rcGeoKey.top;
        if (UGGeoHash::IsIntersect(QueryFetch.rcQueryBounds, rcTemp))
        {
            QueryParameter query;
            query.lGeoKey = QueryFetch.lGeoKey;
            query.lGeoKey <<= 1;
            query.lGeoKey += 1;
            query.lGeoKey <<= 1;
            query.lGeoKey += 1;

            query.nLevel = QueryFetch.nLevel + 1;

            query.rcGeoKey = rcTemp;
            rcTemp.IntersectRect(QueryFetch.rcQueryBounds);
            query.rcQueryBounds = rcTemp;
            query.dPercentage = rcTemp.Width() * rcTemp.Height() * 100 / query.rcGeoKey.Width() / query.rcGeoKey.Height();
            aryRest.Add(query);
        }
        return TRUE;
    }

    YkBool UGGeoHash::GetIntersectHash2(QueryParameter &QueryFetch, YkArray<QueryParameter> &aryRest)
    {

        return TRUE;
    }

    YkBool UGGeoHash::Query(QueryParameter QueryFetch, YkArray<QueryParameter> &aryEquelRest, YkArray<QueryParameter> &aryBetweenRest)
    {
        YkArray<QueryParameter> aryGeoKeys;
        aryGeoKeys.SetGrowSize(32);
        while (TRUE)
        {
            aryGeoKeys.RemoveAll();
            if (QueryFetch.dPercentage < PERCENTAGE)
            {
                UGGeoHash::GetIntersectHash(QueryFetch, aryGeoKeys);
            }
            else
            {
                return TRUE;
            }

            if (aryGeoKeys.GetSize() == 1)
            {
                if (aryGeoKeys[0].dPercentage > PERCENTAGE)
                {
                    aryBetweenRest.Add(aryGeoKeys[0]);
                    break;
                }
                else
                {
                    QueryFetch = aryGeoKeys[0];
                    aryEquelRest.Add(aryGeoKeys[0]);
                }
            }
            else
            {
                for (YkUint i = 0; i < aryGeoKeys.GetSize(); i++)
                {
                    aryBetweenRest.Add(aryGeoKeys[i]);
                }
                break;
            }
        }
        return TRUE;
    }

    YkInt UGGeoHash::GetMinPercentagePos(YkArray<QueryParameter> &aryRest)
    {
        YkInt nPos = 0;
        for (YkUint i = 1; i < aryRest.GetSize(); i++)
        {
            if (aryRest[i].dPercentage < aryRest[nPos].dPercentage)
            {
                nPos = i;
            }
        }
        return nPos;
    }

    YkRect2D UGGeoHash::GetBoundsByKey(YkRect2D IndexBounds, YkLong nKey)
    {
        YkRect2D rc(IndexBounds);
        YkInt n = nKey & 0x3f;
        for (YkInt x = 0; x < n; x++)
        {
            YkDouble dCentX = (rc.left + rc.right) / 2.0;
            YkDouble dCentY = (rc.top + rc.bottom) / 2.0;
            YkLong nMode = nKey >> ((30 - x) * 2);
            YkInt nTemp = 3 & nMode;
            if (nTemp == 0)
            {
                rc.top = dCentY;
                rc.right = dCentX;
            }
            else if (nTemp == 1)
            {
                rc.bottom = dCentY;
                rc.right = dCentX;
            }
            else if (nTemp == 2)
            {
                rc.left = dCentX;
                rc.top = dCentY;
            }
            else
            {
                rc.left = dCentX;
                rc.bottom = dCentY;
            }
        }
        return rc;
    }

    YkBool UGGeoHash::IsIntersect(YkRect2D &rc1, YkRect2D &rc2)
    {
        if (!rc1.IsValid() || !rc2.IsValid())
        {
            return false;
        }
        return (rc1.right > rc2.left) && (rc1.left < rc2.right) && (rc1.top > rc2.bottom) && (rc1.bottom < rc2.top);
    }

    YkString UGGeoHash::GetBetweenFilter1(YkLong nGeoHashKey)
    {
        YkString strFilter;
        YkLong nUpperVal = nGeoHashKey;
        YkInt n = nGeoHashKey & 0x3f;
        YkLong lTemp = 1;
        for (YkInt x = 0; x <= (64 - n * 2 - 4); x++)
        {
            lTemp <<= 1;
            lTemp += 1;
        }
        nUpperVal = nUpperVal | lTemp;
        strFilter.Format(_U(" (geohash >= %lld and geohash <= %lld) "), nGeoHashKey, nUpperVal);
        return strFilter;
    }

    YkString UGGeoHash::GetBetweenFilter2(YkLong nGeoHashKey)
    {
        YkString strFilter;
        YkLong nUpperVal = nGeoHashKey;
        YkInt n = nGeoHashKey & 0x3f;
        YkLong lTemp = 1;
        for (YkInt x = 0; x <= (64 - n * 2 - 4); x++)
        {
            lTemp <<= 1;
            lTemp += 1;
        }
        nUpperVal = nUpperVal | lTemp;
        strFilter.Format(_U(" (ht.SmGeoHashKey >= %lld and ht.SmGeoHashKey <= %lld) "), nGeoHashKey, nUpperVal);
        return strFilter;
    }

    /**
	 * 返回查询条件中权重最小的下标.
	 *
	 * \param aryRest 查询条件数组
	 * \return -1 没有找到,其他值为下标
	 */
	YkInt UGGeoHash::FindLowLevelAndLowPercentage(YkArray<QueryParameter>& aryRest)
	{
		YkInt nPos = -1;
		for (YkUint i = 0; i < aryRest.GetSize(); i++)
		{
			//这里的计算公式为 level * weight * percentage
			if ((aryRest[i].nLevel * WEIGHTS[aryRest[i].nLevel] * aryRest[i].dPercentage) < PERCENTAGE)
			{
				nPos = i;
				break;
			}
		}
		return nPos;
	}

    // UGbool UGGeoHash::test_ComputerGeoHash()
    // {
    //     UGRect2D rcIndex(-180, 90, 180, -90);
    //     UGArray<UGlong> arykeys;
    //     UGRect2D rcgeobounds(1, 45, 45, 1);
    //     UGRect2D rcResult;
    //     UGGeoHash::ComputerGeoHash(rcIndex, arykeys, rcgeobounds);
    //     if (arykeys.GetSize() != 2)
    //     {
    //         return FALSE;
    //     }
    //     arykeys.RemoveAll();
    //     UGGeoHash::ComputerGeoHash(rcIndex, arykeys, rcIndex);
    //     if (arykeys.GetSize() != 1 || arykeys[0] != 0)
    //     {
    //         return FALSE;
    //     }

    //     return TRUE;
    // }

    // UGbool UGGeoHash::test_GetFilter()
    // {
    // 	UGRect2D rcIndex(-180,90,180,-90);
    // 	UGRect2D rcgeobounds(1,45,45,1);
    // 	UGString str = UGGeoHash::GetFilter2(rcIndex,rcgeobounds);
    // 	str = str.TrimLeft().TrimRight();
    // 	if( str != _U("ht.SmGeoHashKey = 0  or  ht.SmGeoHashKey = 3458764513820540929  or  ht.SmGeoHashKey = 3458764513820540930  or  ht.SmGeoHashKey = 3458764513820540931  or  (ht.SmGeoHashKey >= 3458764513820540931 and ht.SmGeoHashKey <= 3530822107858468863)  or  (ht.SmGeoHashKey >= 3530822107858468867 and ht.SmGeoHashKey <= 3602879701896396799)") )
    // 	{
    // 		return FALSE;
    // 	}

    // 	rcgeobounds.left = 0;
    // 	rcgeobounds.bottom = 0;
    // 	rcgeobounds.top = 90;
    // 	rcgeobounds.right = 180;
    // 	str = UGGeoHash::GetFilter2(rcIndex,rcgeobounds);
    // 	str = str.TrimLeft().TrimRight();
    // 	if( str != _U("ht.SmGeoHashKey = 0  or  ht.SmGeoHashKey = 3458764513820540929  or  (ht.SmGeoHashKey >= 3458764513820540929 and ht.SmGeoHashKey <= 4611686018427387903)") )
    // 	{
    // 		return FALSE;
    // 	}

    // 	rcgeobounds.left = 115.438728;
    // 	rcgeobounds.bottom = 39.4970131;
    // 	rcgeobounds.top = 40.1370544;
    // 	rcgeobounds.right = 116.632416;
    // 	str = UGGeoHash::GetFilter2(rcIndex,rcgeobounds);
    // 	str = str.TrimLeft().TrimRight();
    // 	if( str != _U("ht.SmGeoHashKey = 0  or  ht.SmGeoHashKey = 3458764513820540929  or  ht.SmGeoHashKey = 4035225266123964418  or  ht.SmGeoHashKey = 4107282860161892355  or  ht.SmGeoHashKey = 4161326055690338308  or  ht.SmGeoHashKey = 4165829655317708805  or  ht.SmGeoHashKey = 4165829655317708806  or  ht.SmGeoHashKey = 4166392605271130119  or  ht.SmGeoHashKey = 4166462974015307784  or  ht.SmGeoHashKey = 4166462974015307785  or  ht.SmGeoHashKey = 4166498158387396617  or  ht.SmGeoHashKey = 4166462974015307786  or  ht.SmGeoHashKey = 4166462974015307787  or  ht.SmGeoHashKey = 4166463798649028620  or  ht.SmGeoHashKey = 4166463798649028621  or  ht.SmGeoHashKey = 4166463850188636174  or  ht.SmGeoHashKey = 4166463858778570767  or  ht.SmGeoHashKey = 4166463859852312592  or  ht.SmGeoHashKey = 4166463860389183505  or  (ht.SmGeoHashKey >= 4166392605271130120 and ht.SmGeoHashKey <= 4166462974015307775)  or  (ht.SmGeoHashKey >= 4166471770108329994 and ht.SmGeoHashKey <= 4166476168154841087)  or  (ht.SmGeoHashKey >= 4166498158387396618 and ht.SmGeoHashKey <= 4166502556433907711)  or  (ht.SmGeoHashKey >= 4166506954480418826 and ht.SmGeoHashKey <= 4166511352526929919)  or  (ht.SmGeoHashKey >= 4166465173038563339 and ht.SmGeoHashKey <= 4166466272550191103)  or  (ht.SmGeoHashKey >= 4166463523771121676 and ht.SmGeoHashKey <= 4166463798649028607)  or  (ht.SmGeoHashKey >= 4166463936087982093 and ht.SmGeoHashKey <= 4166464004807458815)  or  (ht.SmGeoHashKey >= 4166463833008766990 and ht.SmGeoHashKey <= 4166463850188636159)  or  (ht.SmGeoHashKey >= 4166463858778570768 and ht.SmGeoHashKey <= 4166463859852312575)  or  (ht.SmGeoHashKey >= 4166463860926054416 and ht.SmGeoHashKey <= 4166463861999796223)  or  (ht.SmGeoHashKey >= 4166463861999796240 and ht.SmGeoHashKey <= 4166463863073538047)  or  (ht.SmGeoHashKey >= 4166463860523401234 and ht.SmGeoHashKey <= 4166463860590510079)  or  (ht.SmGeoHashKey >= 4166463860590510098 and ht.SmGeoHashKey <= 4166463860657618943)") )
    // 	{
    // 		return FALSE;
    // 	}

    // 	rcgeobounds.left = 116.438728;
    // 	rcgeobounds.bottom = 40.0970131;
    // 	rcgeobounds.top = 40.1370544;
    // 	rcgeobounds.right = 116.632416;
    // 	str = UGGeoHash::GetFilter2(rcIndex,rcgeobounds);
    // 	str = str.TrimLeft().TrimRight();
    // 	if( str != _U("ht.SmGeoHashKey = 0  or  ht.SmGeoHashKey = 3458764513820540929  or  ht.SmGeoHashKey = 4035225266123964418  or  ht.SmGeoHashKey = 4107282860161892355  or  ht.SmGeoHashKey = 4161326055690338308  or  ht.SmGeoHashKey = 4165829655317708805  or  ht.SmGeoHashKey = 4165829655317708806  or  ht.SmGeoHashKey = 4166392605271130119  or  ht.SmGeoHashKey = 4166462974015307784  or  ht.SmGeoHashKey = 4166498158387396617  or  ht.SmGeoHashKey = 4166506954480418826  or  ht.SmGeoHashKey = 4166509153503674379  or  ht.SmGeoHashKey = 4166509978137395212  or  ht.SmGeoHashKey = 4166509978137395213  or  ht.SmGeoHashKey = 4166509703259488268  or  ht.SmGeoHashKey = 4166509703259488269  or  ht.SmGeoHashKey = 4166509720439357454  or  ht.SmGeoHashKey = 4166509724734324751  or  ht.SmGeoHashKey = 4166509995317264398  or  ht.SmGeoHashKey = 4166509995317264399  or  ht.SmGeoHashKey = 4166509724734324752  or  ht.SmGeoHashKey = 4166509725002760209  or  (ht.SmGeoHashKey >= 4166506954480418827 and ht.SmGeoHashKey <= 4166508053992046591)  or  (ht.SmGeoHashKey >= 4166509153503674380 and ht.SmGeoHashKey <= 4166509428381581311)  or  (ht.SmGeoHashKey >= 4166509428381581324 and ht.SmGeoHashKey <= 4166509703259488255)  or  (ht.SmGeoHashKey >= 4166509978137395214 and ht.SmGeoHashKey <= 4166509995317264383)  or  (ht.SmGeoHashKey >= 4166509771978965005 and ht.SmGeoHashKey <= 4166509840698441727)  or  (ht.SmGeoHashKey >= 4166509725808066576 and ht.SmGeoHashKey <= 4166509726881808383)  or  (ht.SmGeoHashKey >= 4166509995317264400 and ht.SmGeoHashKey <= 4166509996391006207)  or  (ht.SmGeoHashKey >= 4166509996391006224 and ht.SmGeoHashKey <= 4166509997464748031)  or  (ht.SmGeoHashKey >= 4166509725069869074 and ht.SmGeoHashKey <= 4166509725136977919)  or  (ht.SmGeoHashKey >= 4166509725204086802 and ht.SmGeoHashKey <= 4166509725271195647)") )
    // 	{
    // 		return FALSE;
    // 	}
    // 	return TRUE;
    // }
    // UGbool UGGeoHash::test_GetBoundsByKey()
    // {
    // 	/*
    // 	if( GetInfo()->GetIndexType() == IdxGeoHash )
    // 	{
    // 		UGDatasetVector *pDT = (UGDatasetVector *)this->GetDataSource()->GetDataset(_U("New_Region"));
    // 		pDT->Open();
    // 		UGQueryDef query;
    // 		query.m_nCursorType = UGQueryDef::OpenDynamic;

    // 		UGRecordset *prs = pDT->Query(query);
    // 		UGString strSQL;
    // 		strSQL.Format(_U("Select * from Sm_GeoHash_smdtv_%d"),GetID());
    // 		UGODBCCICursor cursor(GetConnection());
    // 		try
    // 		{
    // 			cursor.Open();
    // 			UGlong nKey;
    // 			UGint nID;
    // 			UGRect2D rcIndexBounds(-180.0,90.0,180.0,-90.0);
    // 			UGRect2D rect;
    // 			cursor.Prepare(strSQL);
    // 			cursor.DefineByPos(1,&nKey, 8, NULL, odbcBigInt);
    // 			cursor.DefineByPos(2,&nID, 4, NULL, odbcLong);
    // 			cursor.Execute(__LINE__,__UGFILE__,_U(""));
    // 			SQLRETURN rc = cursor.Fetch();
    // 			while( SQL_SUCCEEDED(rc) )
    // 			{
    // 				rect = UGGeoHash::GetBoundsByKey(rcIndexBounds,nKey);
    // 				UGGeoRegion geo;
    // 				geo.Make(rect);
    // 				prs->AddNew(&geo);
    // 				prs->SetFieldValue(_U("SmUserID"),UGVariant(nID));
    // 				prs->Update();
    // 				rc = cursor.Fetch();
    // 			}
    // 			cursor.Close();
    // 		}
    // 		catch ( UGODBCCIException* e )
    // 		{
    // 			delete e;
    // 			e = NULL;
    // 			cursor.Close();
    // 		}
    // 	}
    // 	*/

    // 	UGRect2D rcIndex(-180,90,180,-90);
    // 	UGArray<UGlong> arykeys;
    // 	UGRect2D rcgeobounds(1,45,45,1);
    // 	UGRect2D rcResult;
    // 	UGGeoHash::ComputerGeoHash(rcIndex,arykeys,rcgeobounds);
    // 	UGRect2D rc = UGGeoHash::GetBoundsByKey(rcIndex,arykeys[0]);
    // 	return UGIS0(rc.left -0.0 );
    // }

    // UGbool UGGeoHash::test_ComputerPointGeoHash()
    // {

    // 	UGRect2D rcIndex(-180,90,180,-90);
    // 	UGRect2D rcgeobounds(45.02,45.02,45.02,45.02);
    // 	UGArray<UGlong> arykeys;
    // 	UGGeoHash::ComputerGeoHash(rcIndex,arykeys,rcgeobounds);

    // 	UGPoint2D pnt(45.02,45.02);
    // 	UGlong lPkey = 0;
    // 	UGGeoHash::ComputerPointGeoHash(rcIndex,lPkey,pnt);
    // 	return TRUE;
    // }

    // UGbool UGGeoHash::test_ComputerPointGeoHash1()
    // {

    // 	UGRect2D rcIndex(-180,90,180,-90);
    // 	UGRect2D rcgeobounds(45.02,45.02,45.02,45.02);
    // 	UGArray<UGlong> arykeys;

    // 	UGint nTimes = 10000;
    // 	for (int i = 0; i < nTimes; i++)
    // 	{
    // 		arykeys.RemoveAll();
    // 		UGGeoHash::ComputerGeoHash(rcIndex,arykeys,rcgeobounds);
    // 	}
    // 	UGPoint2D pnt(45.02,45.02);
    // 	UGlong lPkey = 0;

    // 	for (int i = 0; i < nTimes; i++)
    // 	{
    // 		UGGeoHash::ComputerPointGeoHash(rcIndex,lPkey,pnt);
    // 	}
    // 	return TRUE;
    // }

    // UGbool UGGeoHash::test_ComputerGeoHash2()
    // {
    // 	UGRect2D rcIndex(-180,90,180,-90);
    // 	UGArray<UGlong> arykeys;
    // 	//UGRect2D rcgeobounds(-89,44,89,-44);
    // 	UGRect2D rcgeobounds(-91,46,91,-46);
    // 	UGRect2D rcResult;
    // 	UGGeoHash::ComputerGeoHash(rcIndex,arykeys,rcgeobounds,25,4);
    // 	if ( arykeys.GetSize() != 4 )
    // 	{
    // 		return  FALSE;
    // 	}
    // 	UGArray<UGlong> arykeys2;
    // 	UGGeoHash::ComputerGeoHash2(rcIndex,arykeys2,rcgeobounds);

    // 	UGSort<UGlong >::QSort(arykeys.GetData(), 0, arykeys.GetSize()-1);
    // 	if( arykeys[0] != arykeys2[0] || arykeys[1] != arykeys2[1] )
    // 	{
    // 		return FALSE;
    // 	}

    // 	UGArray<UGlong> arykeys3;
    // 	UGGeoHash::ComputerGeoHash2(rcIndex,arykeys3,rcIndex);
    // 	if( arykeys3.GetSize() != 1 || arykeys3[0] != 0)
    // 	{
    // 		return FALSE;
    // 	}

    // 	return FALSE;
    // }

}