#!/usr/bin/python

# tz_google_earth.py
#       --copyright--                   Copyright 2007 (C) Tranzoa, Co. All rights reserved.    Warranty: You're free and on your own here. This code is not necessarily up-to-date or of public quality.
#       --url--                         http://www.tranzoa.net/tzpython/
#       --email--                       pycode is the name to send to. tranzoa.com is the place to send to.
#       --bodstamps--
#       July 4, 2007            bar
#       July 5, 2007            bar     maps
#                                       maps url is hybrid now
#       July 24, 2007           bar     continue to muck with the logic
#       October 17, 2007        bar     the words "from" and "to" cannot be in google maps urls (the tell gm to give directions)
#       November 18, 2007       bar     turn on doxygen
#       November 27, 2007       bar     insert boilerplate copyright
#       March 14, 2008          bar     timeout
#                                       use elapsed_time()
#       May 17, 2008            bar     email adr
#       August 2, 2009          bar     get around a bug in Google Maps. wordaround: add &ll=lat,lon&lwloc=near to the url
#       November 29, 2011       bar     pyflake cleanup
#       May 27, 2012            bar     doxygen namespace
#       --eodstamps--
##      \file
#       \namespace              tzpython.tz_google_earth
#
#
#       Google Earth and Maps stuff.
#
#       API:
#           http://earth.google.com/comapi/interfaceIApplicationGE.html
#
#
#       Note:
#
#           See the note below in __init__
#
#


import  os
import  re
import  sys
import  time
import  tempfile
import  urllib
from    types   import  FloatType

import  tzlib


noway       = True
try :
    import  win32com.client
    import  pywintypes
    noway   = False
except :
    pass



class   a_google_earth_exception(Exception) :
        pass


class   a_google_earth :

    #
    #       API at http://earth.google.com/comapi/
    #

    IID_IApplicationGE      = '{2830837B-D4E8-48C6-B6EE-04633372ABE4}'
    CLSID_ApplicationGE     = '{8097D7E9-DB9E-4AEF-9B28-61D82A1DF784}'
    GE_ApplicationName      = "GoogleEarth.ApplicationGE"


    def _ready(me) :
        try :
            if  not me.ge.IsInitialized() :
                return(False)
            pass
        except pywintypes.com_error :
            me.temp_places  = None
            me.ge  = win32com.client.Dispatch(me.GE_ApplicationName)        # me.CLSID_ApplicationGE)
            return(False)

        if  not me.ge.IsOnline() :
            return(False)

        return(True)


    def _wait_until_ready(me) :
        while not me._ready() :
            time.sleep(0.1)
        pass



    def __init__(me, global_kml_file = True) :

        if  noway :
            raise   a_google_earth_exception("I can use Google Earth only on Windows for now!")

        #
        #
        #       If you create one of these things (call __init__) from a thread,
        #          it's likely that you will need to call pythoncom.CoInitialize() going in to the thread
        #          and pythoncom.CoUninitialize() going out.
        #
        #       Otherwise, you'll see 'CoInitialize has not been called' exceptions in this call.
        #
        #
        me.ge  = win32com.client.Dispatch(me.GE_ApplicationName)            # me.CLSID_ApplicationGE)

        while   not me.ge.IsInitialized() :
            pass

        while   not me.ge.IsOnline() :
            pass

        tfn                     = ""
        if  not global_kml_file :
            tfn                 = str(os.getpid()) + str(me)
        tfn                     = tzlib.file_name_able("tz_google_earth" + tfn).replace(" ", "").replace(".", "") + ".kml"
        me.temp_kml_file_name   = os.path.join(tempfile.gettempdir(), tfn)

        me.temp_places          = None

        # print me.temp_kml_file_name

        me.allow_new_camera     = True

        pass



    def is_all_streamed(me) :
        return(me.ge.StreamingProgressPercentage >= 100)



    def get_temp_places(me) :
        if  not me.temp_places :
            try :
                me.temp_places  = me.ge.GetTemporaryPlaces()
                # print me.temp_places
                me.temp_places.Visibility   = True
                me.temp_children    = me.temp_places.GetChildren()

                if  False :
                    #   print me.temp_children
                    if  len(me.temp_children) :
                        print "First temp child name", me.temp_children[0].Name
                    pass

                return(True)

            except pywintypes.com_error :
                # e       = sys.exc_info()
                # print   e[0], e[1], e[2]
                pass

            return(False)

        return(True)



    def load_kml_file(me, file_name, allow_new_camera = None, timeout = 35.0) :
        timeout = timeout or 35.0

        if  allow_new_camera != None :
            me.allow_new_camera = allow_new_camera

        if  os.path.isfile(file_name) :

            t   = tzlib.elapsed_time()

            while True :

                if  me._ready() and me.is_all_streamed() :                              # actually, it's a bit after this that the file can be loaded
                    try :
                        if  True :
                            cam = me.ge.GetCamera(True)
                            me.ge.OpenKmlFile(file_name, True)                          # note: True suppresses fusses about it already being in GE
                            if  not me.allow_new_camera :
                                me.ge.SetCamera(cam, 100.0)                             # note: this 100.0 is just some number I put in
                            me.allow_new_camera = False                                 # next time around, don't change the camera unless he explicitely says to do so
                            pass
                        else :
                            fi  = open(file_name, "r")
                            fd  = fi.read()
                            fi.close()
                            me.ge.LoadKmlData(fd)                                       # this just adds stuff, it does not replace the old stuff. ID's don't matter, nor does the folder name or id or description.

                        me.get_temp_places()

                        return(True)

                    except pywintypes.com_error :
                        # e       = sys.exc_info()
                        # print   e[0], e[1], e[2]
                        break                                                           # when GE starts up, this is common (I get 3 of 'em), but the file is loaded!  And maybe the camera changes.

                    except :
                        # e       = sys.exc_info()
                        # print   "ending with", e[0], e[1], e[2]
                        break

                    pass

                if  tzlib.elapsed_time() - t > timeout :

                    break

                time.sleep(0.1)

            pass

        return(False)



    def load_kml_string(me, s, allow_new_camera = None, erase_file = True, timeout = None) :

        fo  = open(me.temp_kml_file_name, "w")
        fo.write(s)
        fo.close()

        retval  = me.load_kml_file(me.temp_kml_file_name, allow_new_camera, timeout)    # GE replaces data if it's from the same URL / file name

        if  erase_file :
            os.remove(me.temp_kml_file_name)

        return(retval)




    def get_feature_by_name(me, name) :                                                 # for example.  The Visibility property can be read and set on the returned value.
        return(me.ge.GetFeatureByName(name))



    pass



#
#       http://mapki.com/wiki/Google_Map_Parameters
#

from_re = re.compile("\s(from\s)",  re.IGNORECASE)
to_re   = re.compile("\s(to\s)",    re.IGNORECASE)
near_re = re.compile("\s(near\s)",  re.IGNORECASE)
loc_re  = re.compile("\s(loc:)",    re.IGNORECASE)

def google_maps_lat_lon_url(lat_or_LatLonTuple, lon = None, description = None) :
    """
        Return a Google maps URL for the given decimal latitude and longitude.
    """

    if  (lon == None) and not isinstance(lat_or_LatLonTuple, FloatType) :
        if  not lat_or_LatLonTuple :
            return("")

        lon                 = lat_or_LatLonTuple[1]
        lat_or_LatLonTuple  = lat_or_LatLonTuple[0]

    description = description or ""
    if  description :
        description = from_re.sub("\xa0" + r"\1", description)
        description = to_re.sub(  "\xa0" + r"\1", description)
        description = near_re.sub("\xa0" + r"\1", description)
        description = loc_re.sub( "\xa0" + r"\1", description)
        description = "(" + urllib.quote_plus(description) + ")"

    return("http://maps.google.com/maps?t=h&z=14&q=%f,%f%s&ll=%f,%f&lwloc=near" % ( lat_or_LatLonTuple, lon, description, lat_or_LatLonTuple, lon, ) )










if  __name__ == '__main__' :

    sys.argv.pop(0)

    fn      = "x.kml"
    if  len(sys.argv) :
        fn  = sys.argv.pop(0)

    fi  = open(fn, "r")
    fd  = fi.read()
    fi.close()

    ge  = a_google_earth()
    ge.load_kml_string(fd)

    pass


#
#
# eof
