class WindowRecord(SimpleBuilderApp):
    def __init__(self, equipment_service, data_path = None, listSport = None, parent = None, date = None, title=None, distance=None, time=None, upositive=None, unegative=None, bpm=None, calories=None, comment=None, windowTitle=None, equipment=[]):
        logging.debug(">>")
        self.parent = parent
        self.pytrainer_main = parent.pytrainer_main
        self.uc = UC()
        logging.debug("Using US system: %s", self.uc.us)
        self.data_path = data_path
        self.mode = "newrecord"
        self.id_record = ""
        self.store = None
        self.active_row = None
        self.activity_data = [] 
        SimpleBuilderApp.__init__(self, "newrecord.ui")
        self.conf_options = [
            "rcd_date",
            "rcd_sport",
            "rcd_distance",
            "rcd_beats",
            "rcd_comments",
            "rcd_average",
            "rcd_calories",
            "rcd_title",
            "rcd_gpxfile",
            "rcd_upositive",
            "rcd_unegative",
            "rcd_maxbeats",
            "rcd_pace",
            "rcd_maxpace",
            "rcd_maxvel",
            ]
        self.listSport = {}
        for sport in listSport:
            self.listSport[sport.id] = sport.name
        for i in self.listSport:    
            self.rcd_sport.insert_text(i,self.listSport[i])
        self.rcd_sport.set_active(0)

        if windowTitle is not None:
            self.newrecord.set_title(windowTitle)
        if date != None:
            self.setDate(date)
        if title != None:
            self.rcd_title.set_text(title)
        if distance != None:
            #self.rcd_distance.set_text(distance)
            #myset_text(rcd_distance, 'distance', distance, us=self.us, round=2)
            self.rcd_distance.set_text(self.uc.distance(distance))
        if time != None:
            self.setTime(time)
        if distance!=None and time!=None:
            self.on_calcavs_clicked(None)
        if upositive != None:
            self.rcd_upositive.set_text(self.uc.height(upositive))
        if unegative != None:
            self.rcd_unegative.set_text(self.uc.height(unegative))
        if calories != None:
            self.rcd_calories.set_text(calories)
            
        #populate labels with units        
        self.label_rcd_distance.set_text(_('Distance') + ' (%s)' %self.uc.unit_distance)
        self.label_rcd_maxvel.set_text(_('Max') + ' (%s)' %self.uc.unit_speed)
        self.label_rcd_average.set_text(_('Average') + ' (%s)' %self.uc.unit_speed)
        self.label_rcd_maxpace.set_text(_('Max') + ' (%s)' %self.uc.unit_pace)
        self.label_rcd_pace.set_text(_('Pace') + ' (%s)' %self.uc.unit_pace)
        self.label_rcd_upositive.set_text(_('Ascent') + ' (%s)' %self.uc.unit_height)
        self.label_rcd_unegative.set_text(_('Descent') + ' (%s)' %self.uc.unit_height)        

        self._init_equipment(equipment, equipment_service)
        logging.debug("<<")
        
    def _init_equipment(self, selected_equipment, equipment_service):
        equipment = {}
        active_equipment = equipment_service.get_active_equipment()
        for item in active_equipment:
            equipment[item] = False
        if len(active_equipment) == 0:
            self.noActiveEquipmentMessageContainer.set_visible(True)
        for item in selected_equipment:
            equipment[item] = True
        list_store = Gtk.ListStore(int, str, bool)
        for item in equipment:
            list_store.append((item.id, item.description, equipment[item]))
        tree_view = self.treeviewRecordEquipment
        cell_renderer = Gtk.CellRendererToggle()
        cell_renderer.connect('toggled', self._equipment_selection_toggled)
        tree_view.append_column(Gtk.TreeViewColumn("Selected", cell_renderer, active=2))
        tree_view.append_column(Gtk.TreeViewColumn("Equipment Item", Gtk.CellRendererText(), text=1))
        tree_view.set_model(list_store)
    
    def _equipment_selection_toggled(self, widget, path):
        list_store = self.treeviewRecordEquipment.get_model()
        iter = list_store.get_iter(path)
        value = list_store.get_value(iter, 2)
        list_store.set(iter, 2, not value)
    
    def _get_selected_equipment_ids(self):
        selected_ids = []
        list_store = self.treeviewRecordEquipment.get_model()
        iter = list_store.get_iter_first()
        while iter is not None:
            id = list_store.get_value(iter, 0)
            selected = list_store.get_value(iter, 2)
            if selected:
                selected_ids.append(id)
            iter = list_store.iter_next(iter)
        return selected_ids
    
    def getActivityData(self):
        return self.activity_data
        
    def populateMultiWindow(self, activities):
        logging.debug(">>")
        self.mode = "multiple_activities"
        #activities (activity_id, start_time, distance, duration, sport, gpx_file, file_id)
        self.activity_data = []
        #Make treeview
        self.store = self.build_tree_view()
        #Add data
        for activity in activities:
            iter = self.store.append()
            self.store.set(
                    iter,
                    0, activity[0],
                    1, activity[1],
                    2, activity[2],
                    3, activity[3],
                    4, activity[4],
                    5, activity[5]
                    )
            details = {}
            details["complete"]  = False
            details["rcd_distance"] = activity[2]
            duration = activity[3]
            if duration.count(":") == 2:
                hours, mins, secs = duration.split(":")
            else:
                hours = mins = secs = 0
            #details["rcd_hour"] = float(hours)
            #details["rcd_min"] = float(mins)
            #details["rcd_second"] = float(secs)
            #details["rcd_time"] = (((float(hours) * 60) + float(mins)) * 60) + float(secs)
            details["activity_id"] = activity[0]
            details["rcd_time"] = (float(hours), float(mins), float(secs))
            if activity[4] is not None:
                details["rcd_sport"] = activity[4]
            else:
                # No sport was provided, preliminary set the current selection from window
                details["rcd_sport"] = gtk_str(self.rcd_sport.get_active_text())
            details["rcd_gpxfile"] = activity[5]
            details["file_id"] = activity[6]
            self.activity_data.append(details)
        self.scrolledwindowEntries.show_all()
        #Hide some of the buttons
        self.button25.hide() #GPX file "Open" button
        self.button24.hide() #GPX file "Calculate Values" button
        self.button10.hide() #Distance "Calculate" button
        self.button11.hide() #Duration "Calculate" button
        #self.button12.hide() #Velocity "Calculate" button
        self.button43.hide() #Pace "Calculate" button
        #Make GPX file 'unsensitive'
        self.rcd_gpxfile.set_sensitive(0)       
        while Gtk.events_pending(): # This allows the GUI to update
            Gtk.main_iteration()    # before completion of this entire action
        #Select first row and display details
        self.treeviewEntries.set_cursor(0)  
        self.show_treeviewEntries_row(0)
        logging.debug("<<")
        
    def build_tree_view(self):
        store = Gtk.ListStore(  GObject.TYPE_STRING,
                                GObject.TYPE_STRING,
                                GObject.TYPE_STRING,
                                GObject.TYPE_STRING,
                                GObject.TYPE_STRING,
                                GObject.TYPE_STRING )
        column_names=["id", _("Start Time"), _("Distance"),_("Duration"),_("Sport"), _("GPX File")]
        for column_index, column_name in enumerate(column_names):
            #Add columns
            column = Gtk.TreeViewColumn(column_name, Gtk.CellRendererText(), text=column_index)
            column.set_sort_column_id(column_index)
            if column_name == "id":
                column.set_visible(False)
            column.set_resizable(True)
            self.treeviewEntries.append_column(column)
        self.treeviewEntries.set_headers_clickable(True)
        self.treeviewEntries.set_model(store)
        return store
        
    def on_accept_clicked(self,widget):
        logging.debug(">>")
        if self.mode == "multiple_activities":
            logging.debug("multiple_activities")
            #Check for edited data in comments
            if self.active_row is not None:
                buffer = self.rcd_comments.get_buffer()
                start,end = buffer.get_bounds()
                comments = gtk_str(buffer.get_text(start,end, True))
                self.activity_data[self.active_row]["rcd_comments"] = comments
                #Advanced tab items
                self.activity_data[self.active_row]["rcd_maxpace"] = gtk_str(self.rcd_maxpace.get_text())
                self.activity_data[self.active_row]["rcd_pace"] = gtk_str(self.rcd_pace.get_text())
                self.activity_data[self.active_row]["rcd_upositive"] = gtk_str(self.rcd_upositive.get_text())
                self.activity_data[self.active_row]["rcd_unegative"] = gtk_str(self.rcd_unegative.get_text())
                self.activity_data[self.active_row]["rcd_maxbeats"] = gtk_str(self.rcd_maxbeats.get_text())
                self.activity_data[self.active_row]["rcd_beats"] = gtk_str(self.rcd_beats.get_text())
                self.activity_data[self.active_row]["rcd_calories"] = gtk_str(self.rcd_calories.get_text())
            row = 0 
            for activity in self.activity_data:
                index = self.activity_data.index(activity)
                if activity["complete"] is False:
                    #Did not view or modify this record - need to get all the details
                    logging.debug("Activity incomplete.. %s", activity["rcd_gpxfile"])
                    self.update_activity_data(row, activity["rcd_gpxfile"], activity["rcd_sport"])
                activity["rcd_title"] = activity["rcd_title"].replace("\"","'")
                #Add activity to DB etc
                laps = activity.pop("laps", ())
                selected_equipment_ids = self._get_selected_equipment_ids()
                self.activity_data[index]["db_id"] = self.parent.insertRecord(activity, laps, equipment=selected_equipment_ids)
                row += 1
            logging.debug("Processed %d rows of activity data", row)
        else:
            logging.debug("Single activity")
            list_options = {}
            trackSummary = {}
            list_options["rcd_date"] = gtk_str(self.rcd_date.get_text())
            list_options["rcd_sport"] = gtk_str(self.rcd_sport.get_active_text())
            list_options["rcd_distance"] = self.uc.usr2sys_str('distance',
                                                               gtk_str(self.rcd_distance.get_text()))
            list_options["rcd_beats"] = gtk_str(self.rcd_beats.get_text())
            list_options["rcd_average"] = self.uc.usr2sys_str('speed',
                                                              gtk_str(self.rcd_average.get_text()))
            list_options["rcd_calories"] = gtk_str(self.rcd_calories.get_text())
            list_options["rcd_title"] = gtk_str(self.rcd_title.get_text())
            list_options["rcd_gpxfile"] = gtk_str(self.rcd_gpxfile.get_text())
            list_options["rcd_upositive"] = self.uc.usr2sys_str('height',
                                                                gtk_str(self.rcd_upositive.get_text()))
            list_options["rcd_unegative"] = self.uc.usr2sys_str('height',
                                                                gtk_str(self.rcd_unegative.get_text()))
            list_options["rcd_maxbeats"] = gtk_str(self.rcd_maxbeats.get_text())
            # 2011.11.05 - dgranda
            # Pace is shown to user in mm:ss format
            # But pace in database is stored in a mixed way: 4.30 for 4:30 (4.5 in 'decimal'). This needs to be changed!!
            list_options["rcd_pace"] = self.uc.usr2sys_str('pace', gtk_str(self.rcd_pace.get_text()).replace(":","."))
            list_options["rcd_maxpace"] = self.uc.usr2sys_str('pace', gtk_str(self.rcd_maxpace.get_text()).replace(":","."))
            list_options["rcd_maxvel"] = self.uc.usr2sys_str('speed', gtk_str(self.rcd_maxvel.get_text()))
            list_options["rcd_time"] = [self.rcd_hour.get_value_as_int(),self.rcd_min.get_value_as_int(),self.rcd_second.get_value_as_int()]
            buffer = self.rcd_comments.get_buffer()
            start,end = buffer.get_bounds()
            comment = gtk_str(buffer.get_text(start,end, True))
            list_options["rcd_comments"] = comment
            selected_equipment_ids = self._get_selected_equipment_ids()
            # Added to change start time, only activities without GPX+ source file - dgranda 2011/06/10
            record_time = gtk_str(self.rcd_starttime.get_text())
            record_date = gtk_str(self.rcd_date.get_text())
            localtz = getLocalTZ()
            date = dateutil.parser.parse(record_date+" "+record_time+" "+localtz)
            local_date = str(date)
            utc_date = date.astimezone(tzutc()).strftime("%Y-%m-%dT%H:%M:%SZ")
            list_options["date_time_utc"] = utc_date
            list_options["date_time_local"] = local_date

            if self.mode == "newrecord":
                logging.debug('Track data: %s', list_options)
                if list_options["rcd_gpxfile"] != "":
                    logging.info('Adding new activity based on GPX file')
                    self.parent.insertRecord(list_options, None, selected_equipment_ids)
                else:
                    logging.info('Adding new activity based on provided data')
                    #Manual entry, calculate time info
                    record_time = gtk_str(self.rcd_starttime.get_text())
                    record_date = gtk_str(self.rcd_date.get_text())
                    localtz = getLocalTZ()
                    date = dateutil.parser.parse(record_date+" "+record_time+" "+localtz)
                    local_date = str(date)
                    utc_date = date.astimezone(tzutc()).strftime("%Y-%m-%dT%H:%M:%SZ")
                    list_options["date_time_utc"] = utc_date
                    list_options["date_time_local"] = local_date

                    try:
                        self.parent.insertRecord(
                                list_options,
                                equipment=selected_equipment_ids)
                    except ValueError:
                        msg = ("Unable to add an activity record without any "
                               "sports, please add a sport in preferences' "
                               "<i>Sports</i> tab.")
                        logging.error(msg)
                        warning_dialog(title=_("Error Adding Activity Record"), text=_(msg))

            elif self.mode == "editrecord":
                self.parent.updateRecord(list_options, self.id_record, equipment=selected_equipment_ids)
        logging.debug("<<")
        self.close_window()
    
    def on_cancel_clicked(self,widget):
        self.close_window()

    def close_window(self, widget=None):
        self.newrecord.hide()
        #self.newrecord = None
        self.quit()

    def on_calendar_clicked(self,widget):
        calendardialog = WindowCalendar(self.data_path,self, date=gtk_str(self.rcd_date.get_text()))
        calendardialog.run()

    def setDate(self,date):
        self.rcd_date.set_text(date)

    def setTime(self,timeInSeconds):
        time_in_hour = int(timeInSeconds)/3600.0
        hour = int(time_in_hour)
        min = int((time_in_hour-hour)*60)
        sec = (((time_in_hour-hour)*60)-min)*60
        self.rcd_hour.set_value(hour)
        self.rcd_min.set_value(min)
        self.rcd_second.set_value(sec)

    def setValue(self,var_name,value, format="%0.2f"):
        var = getattr(self,var_name)
        try:
            valueString = format % value
            var.set_text(valueString)
        except Exception as e:
            logging.debug("setValue: %s, %s, %s", var_name, value, e)
            pass
    
    def setValuesFromActivity(self, activity):
        logging.debug(">>")
        self.mode = "editrecord"
        if activity is None:
            logging.debug("activity is None")
            logging.debug("<<")
            return
        self.id_record = activity.id
        (h, m, s) = activity.time_tuple
        self.rcd_hour.set_value(h)
        self.rcd_min.set_value(m)
        self.rcd_second.set_value(s)
        self.rcd_date.set_text(str(activity.date))
        
        #self.rcd_distance.set_text("%.2f"%activity.distance)
        #myset_text(self.rcd_distance, 'distance', activity.distance, us=self.us, round=2)
        if activity.distance is not None:
            self.rcd_distance.set_text("%.2f" %self.uc.distance(activity.distance))        
        else:
            self.rcd_distance.set_text("")
        self.rcd_average.set_text("%.2f" %self.uc.speed(activity.average))
        self.rcd_calories.set_text("%s"%activity.calories)
        self.rcd_beats.set_text("%s"%activity.beats)
        self.rcd_upositive.set_text("%.2f" %self.uc.height(activity.upositive))
        self.rcd_unegative.set_text("%.2f" %self.uc.height(activity.unegative))
        self.rcd_maxvel.set_text("%.2f" %self.uc.speed(activity.maxspeed))
        self.rcd_maxpace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.maxpace),True)) # value coming from DB
        self.rcd_pace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.pace),True)) # value coming from DB
        self.rcd_maxbeats.set_text("%s"%activity.maxbeats)
        self.rcd_title.set_text(activity.title)
        
        if activity.starttime is not None:
            self.rcd_starttime.set_text("%s" % activity.starttime)
        sportPosition = self.getSportPosition(activity.sport_id)
        self.rcd_sport.set_active(sportPosition) 
        buffer = self.rcd_comments.get_buffer()
        start,end = buffer.get_bounds()
        buffer.set_text(activity.comments)
        if activity.gpx_file is not None:
            self.rcd_gpxfile.set_text(activity.gpx_file)
            self.frameGeneral.set_sensitive(0)      #Currently record values not changed if a GPX file is present
            self.frameVelocity.set_sensitive(0)     #Greying out options to indicate this to user
            self.framePace.set_sensitive(0)
            self.frameElevation.set_sensitive(0)
            self.frameBeats.set_sensitive(0)
        logging.debug("<<")
        
    def setValues(self,values):
        #(24, u'2009-12-26', 4, 23.48, u'9979', 0.0, 8.4716666232200009, 2210, u'', None, u'', 573.0, 562.0, 11.802745244400001, 5.0499999999999998, 7.04, 0.0, u'2009-12-25T19:41:48Z', u'2009-12-26 08:41:48+13:00')
        #(50, u'2006-10-13', 1, 25.0, u'5625', 0.0, 16.0, 0, u'', gpsfile, title,upositive,unegative,maxspeed|maxpace|pace|maxbeats
        logging.debug("windowrecord setValues called")
        self.mode = "editrecord"
        self.id_record = values[0]
        self.setTime(values[4])
        self.rcd_date.set_text(str(values[1]))
        self.setValue("rcd_distance",values[3])
        self.setValue("rcd_average",values[6])
        self.setValue("rcd_calories",values[7], "%0.0f")
        self.setValue("rcd_beats",values[5], "%0.0f")
        self.setValue("rcd_upositive",values[11])
        self.setValue("rcd_unegative",values[12])
        self.setValue("rcd_maxvel",values[13])
        self.setValue("rcd_maxpace",values[14])
        self.setValue("rcd_pace",values[15])
        self.setValue("rcd_maxbeats",values[16], "%0.0f")
        self.rcd_title.set_text("%s"%values[10])
        
        local_time = values[18]
        if local_time is not None:
            dateTime = dateutil.parser.parse(local_time)
            sTime = dateTime.strftime("%X")
            self.rcd_starttime.set_text("%s" % sTime)
        sportID = values[2]
        sportPosition = self.getSportPosition(sportID)
        self.rcd_sport.set_active(sportPosition) 
        buffer = self.rcd_comments.get_buffer()
        start,end = buffer.get_bounds()
        buffer.set_text(values[8])

    def getSportPosition(self, sportID):
        """
            Function to determine the position in the sport array for a given sport ID
            Needed as once sports are deleted there are gaps in the list...
        """
        count = 0
        for key, value in self.listSport.items():
            if key == sportID: 
                return count
            count +=1
        return 0
        
    def getSportPositionByName(self, sport):
        """
            Function to determine the position in the sport array for a given sport 
            Needed as once sports are deleted there are gaps in the list...
        """
        count = 0
        for key, value in self.listSport.items():
            if value == sport: 
                return count
            count +=1
        return None
    
    def on_calctime_clicked(self,widget):
        logging.debug(">>")
        try:
            distance = float(gtk_str(self.rcd_distance.get_text())) # distance is mandatory!
            # we need either pace or speed
            try:
                average = float(gtk_str(self.rcd_average.get_text()))
                time_in_hour = distance/average
                logging.debug("Distance: %0.3f km (mi) | Speed: %0.2f -> Time: %.f hours",
                              distance, average, time_in_hour)
                pace = self.parent.pace_from_float(60/average)
                logging.debug("Setting pace: %s", pace)
                self.rcd_pace.set_text(pace)
            except:
                pace_dec = self.parent.pace_to_float(gtk_str(self.rcd_pace.get_text()))
                time_in_hour = pace_dec*distance/60.0
                logging.debug("Distance: %0.3f km (mi) | Pace_dec: %0.2f -> Time: %.f hours",
                              distance, pace_dec, time_in_hour)
                speed = distance/time_in_hour
                logging.debug("Setting average speed: %0.2f", speed)
                self.rcd_average.set_text("%0.2f" %speed)
            self.set_recordtime(time_in_hour)
        except:
            logging.debug("Traceback: %s" % traceback.format_exc())
            pass
        logging.debug("<<")

    def update_activity_data(self, row, gpx_file, sport):
        logging.debug(">>")
        self.activity_data[row]["rcd_comments"] = ""
        gpx_summary, laps = self.parent.summaryFromGPX(gpx_file, (sport,""))
        local_time = gpx_summary['date_time_local']
        start_date = local_time.strftime("%Y-%m-%d")
        start_time = local_time.strftime("%H:%M:%S")
        self.activity_data[row]["rcd_date"] = start_date
        self.activity_data[row]["rcd_starttime"] = start_time
        self.activity_data[row]["date_time_local"] = gpx_summary['date_time_local']
        self.activity_data[row]["date_time_utc"] = gpx_summary['date_time_utc']
        self.activity_data[row]["rcd_time"] = gpx_summary["rcd_time"]
        self.activity_data[row]["rcd_distance"] = gpx_summary["rcd_distance"]
        self.activity_data[row]["rcd_average"] = gpx_summary["rcd_average"]
        self.activity_data[row]["rcd_calories"] = gpx_summary["rcd_calories"]
        self.activity_data[row]["rcd_beats"] = gpx_summary["rcd_beats"]
        self.activity_data[row]["rcd_upositive"] = gpx_summary["rcd_upositive"]
        self.activity_data[row]["rcd_unegative"] = gpx_summary["rcd_unegative"]
        self.activity_data[row]["rcd_maxvel"] = gpx_summary["rcd_maxvel"]
        self.activity_data[row]["rcd_maxpace"] = gpx_summary["rcd_maxpace"]
        self.activity_data[row]["rcd_pace"] = gpx_summary["rcd_pace"]
        self.activity_data[row]["rcd_maxbeats"] = gpx_summary["rcd_maxbeats"]
        self.activity_data[row]["rcd_title"] = ""
        self.activity_data[row]["laps"] = laps
        self.activity_data[row]["complete"] = True
        logging.debug("<<")

        
    def show_treeviewEntries_row(self, row):
        '''
        Show details of treeview entry
        TODO need to maintain any changes and display those....
        '''
        logging.debug(">>")
        self.active_row = row
        #Get details from stored data
        #set sport
        sport = self.activity_data[row]["rcd_sport"]
        sportPosition = self.getSportPositionByName(sport)
        if sportPosition is not None:
            self.rcd_sport.set_active(sportPosition)
        #Set gpx file name
        gpx_file = self.activity_data[row]["rcd_gpxfile"]
        self.setValue("rcd_gpxfile", gpx_file, "%s")
        #set duration
        time = time2second(self.activity_data[row]["rcd_time"])      #TODO Fix to use timeinseconds!!
        self.setTime(time)                                                  #TODO Fix to use timeinseconds!!
        #Set distance
        self.setValue("rcd_distance",self.activity_data[row]["rcd_distance"], "%s")
        #Set comments
        buffer = self.rcd_comments.get_buffer()
        start,end = buffer.get_bounds()
        if "rcd_comments" not in self.activity_data[row]:
            self.activity_data[row]["rcd_comments"] = ""
        buffer.set_text(self.activity_data[row]["rcd_comments"])
        while Gtk.events_pending(): # This allows the GUI to update
            Gtk.main_iteration()    # before completion of this entire action
        if self.activity_data[row]["complete"] is False:
            #Haven't processed GPX file yet
            #Blank values not yet known
            self.setValue("rcd_date", "", "%s")
            self.setValue("rcd_starttime", "", "%s")
            self.setValue("rcd_average", "", "%s")
            self.setValue("rcd_calories","", "%s")
            self.setValue("rcd_beats", "", "%s")
            self.setValue("rcd_upositive", "", "%s")
            self.setValue("rcd_unegative", "", "%s")
            self.setValue("rcd_maxvel", "", "%s")
            self.rcd_maxpace.set_text("")
            self.rcd_pace.set_text("")
            self.setValue("rcd_maxbeats", "", "%s")
            while Gtk.events_pending(): # This allows the GUI to update
                Gtk.main_iteration()    # before completion of this entire action
            #Get some info from gpx file
            self.update_activity_data(row, gpx_file, sport)
        self.setValue("rcd_distance",self.activity_data[row]["rcd_distance"], "%s") 
        time = time2second(self.activity_data[row]["rcd_time"])
        self.setTime(time)  
        self.setValue("rcd_date", self.activity_data[row]["rcd_date"], "%s")
        self.setValue("rcd_starttime", self.activity_data[row]["rcd_starttime"], "%s")
        self.setValue("rcd_average",self.activity_data[row]["rcd_average"])
        self.setValue("rcd_calories",self.activity_data[row]["rcd_calories"], "%s")
        self.setValue("rcd_beats",self.activity_data[row]["rcd_beats"], "%s")
        self.setValue("rcd_upositive",self.activity_data[row]["rcd_upositive"], "%s")
        self.setValue("rcd_unegative",self.activity_data[row]["rcd_unegative"], "%s")
        self.setValue("rcd_maxvel",self.activity_data[row]["rcd_maxvel"])
        self.rcd_maxpace.set_text(self.activity_data[row]["rcd_maxpace"])
        self.rcd_pace.set_text(self.activity_data[row]["rcd_pace"])
        self.setValue("rcd_maxbeats",self.activity_data[row]["rcd_maxbeats"], "%s")
        self.rcd_title.set_text(self.activity_data[row]["rcd_title"])
        logging.debug("<<")
        
        
    def on_rcd_title_changed(self, widget):
        if self.mode == "multiple_activities" and self.active_row is not None:
            self.activity_data[self.active_row]["rcd_title"] = gtk_str(self.rcd_title.get_text())
            
    def on_rcd_sport_changed(self, widget):
        if self.mode == "multiple_activities" and self.active_row is not None:
            sport = gtk_str(self.rcd_sport.get_active_text())
            #Update sport in data store
            self.activity_data[self.active_row]["rcd_sport"] = sport
            #Update sport in treeview
            self.store[self.active_row][4] = sport
            
    def on_rcd_distance_changed(self, widget):
        if self.mode == "multiple_activities" and self.active_row is not None:
            distance = gtk_str(self.rcd_distance.get_text())
            #Update distance in data store
            self.activity_data[self.active_row]["rcd_distance"] = distance
            #Update distance in treeview
            self.store[self.active_row][2] = distance
            
    def on_rcd_duration_value_changed(self, widget):
        if self.mode == "multiple_activities" and self.active_row is not None:
            hour = self.rcd_hour.get_value()
            min = self.rcd_min.get_value()
            sec = self.rcd_second.get_value()
            #print hour, min, sec
            #Update duration in data store
            self.activity_data[self.active_row]["rcd_time"] = (hour, min, sec)
            #Update duration in treeview
            self.store[self.active_row][3] = "%d:%.2d:%.2d" % (int(hour), int(min), int(sec))
            
    def on_rcd_date_changed(self, widget):
        if self.mode == "multiple_activities" and self.active_row is not None:
            #Update date in data store
            self.activity_data[self.active_row]["rcd_date"] = gtk_str(self.rcd_date.get_text())
            
    def on_rcd_starttime_changed(self, widget):
        if self.mode == "multiple_activities" and self.active_row is not None:
            #Update start time in data store
            self.activity_data[self.active_row]["rcd_starttime"] = gtk_str(self.rcd_starttime.get_text())
            
    def on_treeviewEntries_row_activated(self, treeview, event):
        '''
         Callback to display details of different activity
        '''
        #Check for edited data in previous row
        if self.active_row is not None:
            #Check for edited data in comments
            buffer = self.rcd_comments.get_buffer()
            start,end = buffer.get_bounds()
            comments = gtk_str(buffer.get_text(start,end, True))
            self.activity_data[self.active_row]["rcd_comments"] = comments
            #Advanced tab items
            self.activity_data[self.active_row]["rcd_maxpace"] = gtk_str(self.rcd_maxpace.get_text())
            self.activity_data[self.active_row]["rcd_pace"] = gtk_str(self.rcd_pace.get_text())
            self.activity_data[self.active_row]["rcd_upositive"] = gtk_str(self.rcd_upositive.get_text())
            self.activity_data[self.active_row]["rcd_unegative"] = gtk_str(self.rcd_unegative.get_text())
            self.activity_data[self.active_row]["rcd_maxbeats"] = gtk_str(self.rcd_maxbeats.get_text())
            self.activity_data[self.active_row]["rcd_beats"] = gtk_str(self.rcd_beats.get_text())
            self.activity_data[self.active_row]["rcd_calories"] = gtk_str(self.rcd_calories.get_text())
        #Get row that was selected
        x = int(event.x)
        y = int(event.y)
        time = event.time
        pthinfo = treeview.get_path_at_pos(x, y)
        if pthinfo is not None:
            path, col, cellx, celly = pthinfo
            treeview.grab_focus()
            treeview.set_cursor(path, col, 0)
            while Gtk.events_pending(): # This allows the GUI to update
                Gtk.main_iteration()    # before completion of this entire action
            self.show_treeviewEntries_row(path[0])

    def on_calcavs_clicked(self,widget):
        logging.debug(">>")
        hour = self.rcd_hour.get_value_as_int()
        min = self.rcd_min.get_value_as_int()
        sec = self.rcd_second.get_value_as_int()
        time = sec + (min*60) + (hour*3600)
        if time<1:
            logging.debug("Seems no time value (%s) has been entered, nothing to calculate.", time)
            return False
        distance = float(gtk_str(self.rcd_distance.get_text()))
        if distance<1:
            logging.debug("Seems no distance value (%s) has been entered, nothing to calculate.", distance)
            return False
        logging.debug("Time: %d seconds | Distance: %0.2f km (mi)", time, distance)
        # Average speed        
        average_speed = distance*3600.0/time
        logging.debug("Average speed: %0.2f", average_speed)
        self.rcd_average.set_text("%0.2f" %average_speed)
        # Average pace 
        dec_pace = 60/average_speed
        #Transform pace to mm:ss
        pace = self.parent.pace_from_float(dec_pace)
        logging.debug("Average pace: %s", pace)
        self.rcd_pace.set_text(pace)
        logging.debug("<<")

    def on_calccalories_clicked(self,widget):
        sport = gtk_str(self.rcd_sport.get_active_text())
        hour = self.rcd_hour.get_value_as_int()
        min = self.rcd_min.get_value_as_int()
        sec = self.rcd_second.get_value_as_int()
        hour += float(min)/60.0 + float(sec)/(60.0*60.0)
        weight = self.pytrainer_main.profile.getValue("pytraining","prf_weight")
        try:
            weight = float(weight)
        except:
            weight = 0.0
        try:
            met = float(self.parent.getSportMet(sport))
        except:
            met = None
        try:
            extraweight = self.parent.getSportWeight(sport)
            extraweight = float(extraweight)
        except:
            extraweight = 0.0
        if met is not None:
            calories = met*(weight+extraweight)*hour
            self.rcd_calories.set_text(str(calories))

    def on_calcdistance_clicked(self,widget):
        logging.debug(">>")
        try:
            hour = self.rcd_hour.get_value_as_int()
            min = self.rcd_min.get_value_as_int()
            sec = self.rcd_second.get_value_as_int()
            time = sec + (min*60) + (hour*3600)
            time_in_hour = time/3600.0
            # we need either pace or speed
            try:
                average = float(gtk_str(self.rcd_average.get_text()))
                distance = average*time_in_hour
                logging.debug("Time: %d seconds | Speed: %0.2f -> Distance: %0.3f km (mi)",
                              time, average, distance)
                pace = self.parent.pace_from_float(60/average)
                logging.debug("Setting pace: %s", pace)
                self.rcd_pace.set_text(pace)
            except:
                pace_dec = self.parent.pace_to_float(gtk_str(self.rcd_pace.get_text()))
                distance = time/(60.0*pace_dec)
                logging.debug("Time: %d seconds | Pace_dec: %0.2f -> Distance: %0.3f km (mi)",
                              time, pace_dec, distance)
                speed = distance/time_in_hour
                logging.debug("Setting average speed: %0.2f", speed)
                self.rcd_average.set_text("%0.2f" %speed)
            self.set_distance(distance) 
        except:
            logging.debug("Traceback: %s" % traceback.format_exc())
            pass
        logging.debug("<<")
    
    def set_distance(self,distance):
        self.rcd_distance.set_text("%0.2f" %distance)
        #myset_text(rcd_distance, 'distance', distance, us=self.us, round=2)
        
    def set_maxspeed(self,vel):
        self.rcd_maxvel.set_text("%0.2f" %vel)
            
    def set_maxhr(self,hr):
        self.rcd_maxbeats.set_text("%0.2f" %hr)
            
    def set_recordtime (self,time_in_hour):
        hour = int(time_in_hour)
        min = int((time_in_hour-hour)*60)
        sec = (((time_in_hour-hour)*60)-min)*60
        self.rcd_hour.set_value(hour)
        self.rcd_min.set_value(min)
        self.rcd_second.set_value(sec)

    def on_selectfile_clicked(self,widget):
        logging.debug(">>")
        from pytrainer.gui.dialogs import fileChooserDialog
        selectedFile = fileChooserDialog(title="Choose a Google Earth file (.kml) to import", multiple=False).getFiles()
        if selectedFile is not None:
            self.rcd_gpxfile.set_text(selectedFile[0])
        logging.debug("<<")

    def set_gpxfile(self):
        logging.debug(">>")
        logging.debug("<<")

    def on_calculatevalues_clicked(self,widget):
        gpxfile = gtk_str(self.rcd_gpxfile.get_text())
        if os.path.isfile(gpxfile):
            self.frameGeneral.set_sensitive(0)
            self.frameVelocity.set_sensitive(0) 
            self.parent.actualize_fromgpx(gpxfile) class DialogSelectTrack(SimpleBuilderApp):
	def __init__(self, data_path = None, tracks = None, okmethod = None, gpx = None):
		logging.debug(">>")
		self.okmethod = okmethod
		self.tracks = tracks
		self.gpx = gpx
		SimpleBuilderApp.__init__(self, "selecttrackdialog.ui")
		logging.debug("<<")

	def new(self):		
		#preparamos la lista con los tracks disponibles:
		logging.debug(">>")
		column_names=[_("Track Name"), _("Date")]
		self.create_treeview(self.trkpTreeView,column_names)
		self.actualize_treeview(self.trkpTreeView,self.tracks)
		logging.debug("<<")

	def on_ok_clicked(self,widget):
		logging.debug(">>")
		selected,iter = self.trkpTreeView.get_selection().get_selected()
		if iter:
			trackname = selected.get_value(iter,0)
			logging.debug("selected track: "+trackname)
		self.okmethod(self.gpx,trackname)
		self.closewindow()
		logging.debug("<<")
	
	def on_cancel_clicked(self,widget):
		logging.debug("--")
		self.closewindow()

	def closewindow(self):
		logging.debug("--")
		self.selecttrackdialog.hide()
		#self.selecttrackdialog = None
		self.quit()	
	
	def create_treeview(self,treeview,column_names):
		logging.debug(">>")
		i=0
		for column_index, column_name in enumerate(column_names):
			column = Gtk.TreeViewColumn(column_name, Gtk.CellRendererText(), text=column_index)
			column.set_resizable(True)
			column.set_sort_column_id(i)
			treeview.append_column(column)
			i+=1
		logging.debug("<<")
	
	def actualize_treeview(self, treeview, record_list):
		logging.debug(">>")
		iterOne = False
		store = Gtk.ListStore(
			GObject.TYPE_STRING,
			GObject.TYPE_STRING,
			object)
		for i in record_list:
			iter = store.append()
			if not iterOne:
				iterOne = iter
			store.set (
				iter,
				0, str(i[0]),
				1, str(i[1]))
		treeview.set_model(store)
		if iterOne:
			treeview.get_selection().select_iter(iterOne)
		logging.debug("<<") class Date:
    def __init__(self, calendar=None):
        self.calendar = calendar

    def getDate(self):
        #hack for the gtk calendar widget
        if self.calendar is not None:
            year,month,day = self.calendar.get_date()
            # Selected day might be larger than current month's number of days.
            # Iterate backwards until we find valid date.
            while day >= 1:
                try:
                    # months from gtk calendar are numbered from 0 to 11
                    return datetime.date(year, month + 1, day)
                except ValueError :
                    day -= 1
            raise ValueError("Invalid date supplied: "
                             "day is before 1st of month.")
        else:
            return datetime.date.today()

    def setDate(self,newdate):
        year,month,day = newdate.split("-")
        self.calendar.select_month(int(month)-1,int(year))
        self.calendar.select_day(int(day)) def time2second(time):
    hour,min,sec = time
    return int(sec)+(int(min)*60)+(int(hour)*3600) class Gpx:
    def __init__(self, data_path = None, filename = None, trkname = None):
        logging.debug(">>")
        #print("GPX init-ing")
        global mainNS, timeTag, trackTag, trackPointTag, trackPointTagLast, trackSegTag, elevationTag, nameTag
        self.data_path = data_path
        self.filename = filename
        self.trkname = trkname
        logging.debug("%s|%s|%s", data_path, filename, trkname)
        self.trkpoints = []
        self.vel_array = []
        self.total_dist = 0
        self.total_dist_trkpts = 0
        self.total_time = 0
        self.total_time_trkpts = 0
        self.upositive = 0
        self.unegative = 0
        self.maxvel = 0
        self.maxhr = 0
        self.hr_average = 0
        self.date = ""
        self.start_time = ""
        self.calories= 0
        self.tree = None
        if filename != None:
            if not os.path.isfile(self.filename):
                return None
            logging.debug("parsing content from "+self.filename)
            self.tree = etree.ElementTree(file=filename).getroot()
            if self.tree.get("version") == "1.0":
                #Got an old GPX file
                logging.debug("Old gpx version")
                mainNS = string.Template(".//{http://www.topografix.com/GPX/1/0}$tag")
                timeTag = mainNS.substitute(tag="time")
                trackTag = mainNS.substitute(tag="trk")
                trackPointTag = mainNS.substitute(tag="trkpt")
                trackPointTagLast = mainNS.substitute(tag="trkpt[last()]")
                trackSegTag = mainNS.substitute(tag="trkseg")
                elevationTag = mainNS.substitute(tag="ele")
                nameTag = mainNS.substitute(tag="name")
            else:
                logging.debug("Importing version %s gpx file" % self.tree.get("version"))
                mainNS = string.Template(".//{http://www.topografix.com/GPX/1/1}$tag")
                timeTag = mainNS.substitute(tag="time")
                trackTag = mainNS.substitute(tag="trk")
                trackPointTag = mainNS.substitute(tag="trkpt")
                trackPointTagLast = mainNS.substitute(tag="trkpt[last()]")
                trackSegTag = mainNS.substitute(tag="trkseg")
                elevationTag = mainNS.substitute(tag="ele")
                nameTag = mainNS.substitute(tag="name")
                intensityTag = mainNS.substitute(tag="intensity")

            logging.debug("getting values...")
            self.Values = self._getValues()
        logging.debug("<<")

    def getMaxValues(self):
        return self.total_dist, self.total_time, self.maxvel, self.maxhr

    def getDate(self):
        return self.date

    def getTrackRoutes(self):
        trks = self.tree.findall(trackTag)
        tracks = []
        retorno = []
        for trk in trks:
            nameResult = trk.find(nameTag)
            if nameResult is not None:
                name = nameResult.text
            else:
                name = _("No Name")
            timeResult = trk.find(timeTag)
            if timeResult is not None:
                time_ = timeResult.text # check timezone
                logging.debug("TimeResult: %s" %time_)
                mk_time = getDateTime(time_)[0]
                time_ = mk_time.strftime("%Y-%m-%d")
            else:
                time_ = _("No Data")
            logging.debug("name: "+name+" | time: "+time_)
            tracks.append((name,time_))
        return tracks

    def getUnevenness(self):
        return self.upositive,self.unegative

    def getTrackList(self):
        return self.Values

    def getHeartRateAverage(self):
        return self.hr_average

    def getCalories(self):
        return self.calories

    def getStart_time(self):
        return self.start_time

    def getLaps(self):
        logging.debug(">>")
        lapInfo = []
        if self.tree is None:
            return lapInfo
        tree  = self.tree
        laps = tree.findall(lapTag)
        logging.debug("Found %d laps" % len(laps))
        if len(laps) == 0:
            #Found no laps, so add single lap with totals
            stLat = self.trkpoints[0]['lat']
            stLon = self.trkpoints[0]['lon']
            lat = self.trkpoints[-1]['lat']
            lon = self.trkpoints[-1]['lon']
            logging.debug("total_time: %s" %self.total_time)
            lapInfo.append((self.total_time, lat, lon, self.calories, self.total_dist*1000, stLat, stLon, "active", self.hr_average, self.maxhr, self.maxvel, "manual"))
        else:
            for lap in laps:
                endPoint = lap.find(endPointTag)
                lat = endPoint.get("lat")
                lon = endPoint.get("lon")
                startPoint = lap.find(startPointTag)
                if startPoint is not None:
                    stLat = startPoint.get("lat")
                    stLon = startPoint.get("lon")
                else:
                    stLat, stLon = None, None
                elapsedTime = lap.findtext(elapsedTimeTag)
                if elapsedTime.count(":") == 2: # got a 0:41:42.14 type elasped time
                    hours, mins, secs = elapsedTime.split(":")
                    elapsedTime = str((int(hours) *3600) + (int(mins) * 60) + float(secs))
                calories = lap.findtext(calorieTag)
                distance = lap.findtext(distanceTag)
                logging.info("Found time: %s, start lat: %s, start lon: %s, end lat: %s end lon: %s cal: %s dist: %s " % (elapsedTime, stLat, stLon, lat, lon, calories, distance))
                intensity = lap.findtext(intensityTag).lower()
                trigger_element = lap.find(triggerTag)
                #logging.debug("Trigger element: %s" % etree.tostring(trigger_element))
                if "kind" in trigger_element.keys():
                    trigger = trigger_element.get("kind").lower()
                else:
                    trigger = trigger_element.text.lower()
                # attribute xpath features are only available in 1.3 (python >= 2.7) - 2012/01/28 - dgranda
                lap_summary = lap.findall(summaryTag)
                num_elements = len(lap_summary)
                summary_dict = {"MaximumSpeed": 0,
                                "AverageHeartRateBpm": None,
                                "MaximumHeartRateBpm": None}
                if num_elements > 0:
                    if num_elements == 1: # old _non compliant_ pytrainer estructure
                        #logging.debug("lap_summary[0]: %s" % etree.tostring(lap_summary[0]))
                        for key in list(summary_dict.keys()):
                            summary_dict[key] = lap_summary[0].findtext(mainNS.substitute(tag=key))
                            logging.debug("%s: %s" % (key, summary_dict[key]))
                    else:
                        for summary_element in lap_summary:
                            summary_dict[summary_element.get('name')] = summary_element.text
                            logging.debug("%s: %s" % (summary_element.get('name'), summary_element.text))
                    max_speed = summary_dict["MaximumSpeed"]
                    avg_hr = summary_dict["AverageHeartRateBpm"]
                    max_hr = summary_dict["MaximumHeartRateBpm"]
                else:
                    logging.info("No summary found")
                logging.info("Intensity: %s | Trigger: %s | Max speed: %s | Average hr: %s | Maximum hr: %s" % (intensity, trigger, max_speed, avg_hr, max_hr))
                lapInfo.append((elapsedTime, lat, lon, calories, distance, stLat, stLon, intensity, avg_hr, max_hr, max_speed, trigger))
        logging.debug("<<")
        return lapInfo

    def _getValues(self):
        '''
        Migrated to eTree XML processing 26 Nov 2009 - jblance
        '''
        logging.debug(">>")
        tree  = self.tree
        # Calories data comes within laps. Maybe more than one, adding them together - dgranda 20100114
        # Distance data comes within laps where present as well - dgranda 20110204
        laps = tree.findall(lapTag)
        if laps is not None and laps != "":
            totalDistance = 0
            totalDuration = 0
            for lap in laps:
                lapCalories = lap.findtext(calorieTag)
                if lapCalories:
                    self.calories += int(lapCalories)
                lapDistance = lap.findtext(distanceTag)
                totalDistance += float(lapDistance)
                lapDuration_tmp = lap.findtext(elapsedTimeTag)
                # When retrieving data from TCX file -> seconds (float)
                # When retrieving data from GPX+ file -> hh:mm:ss
                # EAFP -> http://docs.python.org/glossary.html
                try:
                    lapDuration = float(lapDuration_tmp)
                except ValueError:
                    hour,minu,sec = lapDuration_tmp.split(":")
                    lapDuration = float(sec) + int(minu)*60 + int(hour)*3600
                totalDuration += lapDuration 
                logging.info("Lap distance: %s m | Duration: %s s | Calories: %s kcal" % (lapDistance, lapDuration, lapCalories))
            self.total_dist = float(totalDistance/1000.0) # Returning km
            self.total_time = int(totalDuration) # Returning seconds
            logging.info("Laps - Distance: %.02f km | Duration: %d s | Calories: %s kcal" % (self.total_dist, self.total_time, self.calories))
        else:
            laps = []

        retorno = []
        his_vel = []
        last_lat = None
        last_lon = None
        last_time = None
        total_dist = 0
        dist_elapsed = 0 # distance since the last time found
        total_hr = 0
        tmp_alt = 0
        len_validhrpoints = 0
        trkpoints = tree.findall(trackPointTag)
        if trkpoints is None or len(trkpoints) == 0:
            logging.debug( "No trkpoints found in file")
            return retorno
        logging.debug("%d trkpoints in file" % len(trkpoints))

        date_ = tree.find(timeTag).text
        if date_ is None:
            logging.info("time tag is blank")
            self.date = None
        else:
            mk_time = getDateTime(date_)[1] #Local Date
            self.date = mk_time.strftime("%Y-%m-%d")
            self.start_time = mk_time.strftime("%H:%M:%S")
        waiting_points = []
        logging.debug("date: %s | start_time: %s | mk_time: %s" % (self.date, self.start_time, mk_time))

        for i, trkpoint in enumerate(trkpoints):
            #Get data from trkpoint
            try:
                lat = float(trkpoint.get("lat"))
                lon = float(trkpoint.get("lon"))
            except Exception as e:
                logging.debug(str(e))
                lat = lon = None
            if lat is None or lat == "" or lat == 0 or lon is None or lon == "" or lon == 0:
                logging.debug("lat or lon is blank or zero")
                continue
            #get the heart rate value from the gpx extended format file
            hrResult = trkpoint.find(hrTag)
            if hrResult is not None:
                hr = int(hrResult.text)
                len_validhrpoints += 1
                total_hr += hr          #TODO fix
                if hr>self.maxhr:
                    self.maxhr = hr
            else:
                hr = None
            #get the cadence (if present)
            cadResult = trkpoint.find(cadTag)
            if cadResult is not None:
                cadence = int(cadResult.text)
            else:
                cadence = None

            #get the time
            timeResult = trkpoint.find(timeTag)
            if timeResult is not None:
                date_ = timeResult.text
                mk_time = getDateTime(date_)[0]
                time_ = time.mktime(mk_time.timetuple()) #Convert date to seconds
                if i == 0:
                    time_elapsed = 0
                else:
                    time_elapsed = time_ - self.trkpoints[i-1]['time'] if self.trkpoints[i-1]['time'] is not None else 0
                    if time_elapsed > 10:
                        logging.debug("%d seconds from last trkpt, someone took a break!" % time_elapsed)
                        # Calculating average lapse between trackpoints to add it
                        average_lapse = round(self.total_time_trkpts/i)
                        logging.debug("Adding %d seconds (activity average) as lapse from last point" % average_lapse)
                        self.total_time_trkpts += average_lapse
                    else:
                        self.total_time_trkpts += time_elapsed
            else:
                time_ = None
                time_elapsed = None

            #get the elevation
            eleResult = trkpoint.find(elevationTag)
            rel_alt = 0
            if eleResult is not None:
                try:
                    ele = float(eleResult.text)
                    #Calculate elevation change
                    if i != 0:
                        rel_alt = ele - self.trkpoints[i-1]['ele'] if self.trkpoints[i-1]['ele'] is not None else 0
                except Exception as e:
                    logging.debug(str(e))
                    ele = None
            else:
                ele = None
                
            #Get corrected elevation if it exists
            correctedEleResult = trkpoint.find(pyt_eleTag)
            if correctedEleResult is not None:
                try:
                    corEle = float(correctedEleResult.text)
                    #Calculate elevation change
                except Exception as e:
                    logging.debug(str(e))
                    corEle = None
            else:
                corEle = None

            #Calculate climb or decent amount
            #Allow for some 'jitter' in height here
            JITTER_VALUE = 0  #Elevation changes less than this value are not counted in +-
            if abs(rel_alt) < JITTER_VALUE:
                rel_alt = 0
            if rel_alt > 0:
                self.upositive += rel_alt
            elif rel_alt < 0:
                self.unegative -= rel_alt

            #Calculate distance between two points
            if i == 0: #First point
                dist = None
            else:
                dist = self._distance_between_points(lat1=self.trkpoints[i-1]['lat'], lon1=self.trkpoints[i-1]['lon'], lat2=lat, lon2=lon)

            #Accumulate distances
            if dist is not None:
                dist_elapsed += dist #TODO fix
                self.total_dist_trkpts += dist

            #Calculate speed...
            vel = self._calculate_speed(dist, time_elapsed, smoothing_factor=3)
            if vel>self.maxvel:
                self.maxvel=vel

            #The waiting point stuff....
            #This 'fills in' the data for situations where some times are missing from the GPX file
            if time_ is not None:
                if len(waiting_points) > 0:
                    for ((w_total_dist, w_dist, w_alt, w_total_time, w_lat, w_lon, w_hr, w_cadence, w_corEle)) in waiting_points:
                        w_time = (w_dist/dist_elapsed) * time_elapsed
                        w_vel = w_dist/((w_time)/3600.0)
                        w_total_time += w_time
                        logging.info("Time added: %f" % w_time)
                        retorno.append((w_total_dist, w_alt, w_total_time, w_vel, w_lat, w_lon, w_hr, w_cadence, w_corEle))
                    waiting_points = []
                    dist_elapsed = 0
                else:
                    retorno.append((self.total_dist_trkpts,ele, self.total_time,vel,lat,lon,hr,cadence,corEle))
                    dist_elapsed = 0
            else: # time_ is None
                waiting_points.append((self.total_dist_trkpts, dist_elapsed, ele, self.total_time, lat, lon, hr, cadence, corEle))

            #Add to dict of values to trkpoint list
            self.trkpoints.append({ 'id': i,
                                    'lat':lat,
                                    'lon':lon,
                                    'hr':hr,
                                    'cadence':cadence,
                                    'time':time_,
                                    'time_since_previous': time_elapsed,
                                    'time_elapsed': self.total_time_trkpts,
                                    'ele':ele,
                                    'ele_change': rel_alt,
                                    'distance_from_previous': dist,
                                    'elapsed_distance': self.total_dist_trkpts,
                                    'velocity':vel,
                                    'correctedElevation':corEle,

                                })

        #end of for trkpoint in trkpoints loop

        #Calculate averages etc
        self.hr_average = 0
        if len_validhrpoints > 0:
            self.hr_average = total_hr/len_validhrpoints
        # In case there is no other way to calculate distance, we rely on trackpoints (number of trackpoints is configurable!)
        if self.total_dist is None or self.total_dist == 0:
            self.total_dist = self.total_dist_trkpts
        else:
            dist_diff = 1000*(self.total_dist_trkpts - self.total_dist)
            logging.debug("Distance difference between laps and trkpts calculation: %f m" % dist_diff)
        if self.total_time is None or self.total_time == 0:
            self.total_time = self.total_time_trkpts
        else:
            time_diff = self.total_time_trkpts - self.total_time
            logging.debug("Duration difference between laps and trkpts calculation: %d s" % time_diff)
        logging.info("Values - Distance: %.02f km | Duration: %d s | Calories: %s kcal" % (self.total_dist, self.total_time, self.calories))
        logging.debug("<<")
        return retorno

    def _distance_between_points(self, lat1, lon1, lat2, lon2):
        '''
        Function to calculate the distance between two lat, lon points on the earths surface

        History of this function is unknown....
        -- David "no me mates que esto lo escribi hace anhos"
        -- http://faculty.washington.edu/blewis/ocn499/EXER04.htm equation for the distance between 2 points on a spherical earth
        -- 0.01745329252 = number of radians in a degree
        -- 57.29577951 = 1/0.01745329252 or degrees per radian
        requires
            - start lat and lon as floats
            - finish lat and lon as floats

        returns
            - distance between points in kilometers if successful
            - None if any error situation occurs
        '''
        RADIANS_PER_DEGREE = 0.01745329252
        DEGREES_PER_RADIAN = 57.29577951
        #Check for invalid variables
        for var in (lat1, lon1, lat2, lon2):
            if var is None or var == 0 or var == "":   #TODO Need this?? if (float(lat) < -0.000001) or (float(lat) > 0.0000001):
                return None
            if type(var) is not type(float()):
                return None
        #Convert lat and lon from degrees to radians
        last_lat = lat1*RADIANS_PER_DEGREE
        last_lon = lon1*RADIANS_PER_DEGREE
        tmp_lat = lat2*RADIANS_PER_DEGREE
        tmp_lon = lon2*RADIANS_PER_DEGREE
        #Pasamos la distancia de radianes a metros..  creo / We convert the distance from radians to meters
        try:
            dist=math.acos((math.sin(last_lat)*math.sin(tmp_lat))+(math.cos(last_lat)*math.cos(tmp_lat)*math.cos(tmp_lon-last_lon)))*111.302*DEGREES_PER_RADIAN
        except Exception as e:
            logging.debug(str(e))
            dist=None
        return dist

    def _calculate_speed(self, dist_elapsed, time_elapsed, smoothing_factor=3):
        '''Function to calculate moving average for speed'''

        if dist_elapsed is None or dist_elapsed == 0 or time_elapsed is None or time_elapsed == 0:
            velocity = 0
        else:
            velocity = (dist_elapsed/time_elapsed) * 3600 # 3600 to convert km/sec to km/hour
        self.vel_array.append(velocity)
        if len(self.vel_array)>smoothing_factor:
            self.vel_array.pop(0)
        if len(self.vel_array)<smoothing_factor:
            #Got too few numbers to average
            #Pad with duplicates
            for x in range(len(self.vel_array), smoothing_factor):
                self.vel_array.append(velocity)
        vel = 0
        for v in self.vel_array:
            vel+= v
        vel /= smoothing_factor
        return vel

    def getStartTimeFromGPX(self, gpxFile):
        '''03.05.2008 - dgranda
        Retrieves start time from a given gpx file
        args:
            - gpxFile: path to xml file (gpx format)
        returns: tuple (string with start time as UTC timezone - 2008-03-22T12:17:43Z, datetime of time in local timezone)
        '''
        logging.debug(">>")
        date_time = self.tree.find(timeTag) #returns first instance found
        if date_time is None:
            logging.error("Problems when retrieving start time from %s. Please check data integrity",
                          gpxFile)
            return 0
        dateTime = getDateTime(date_time.text)
        zuluDateTime = dateTime[0].strftime("%Y-%m-%dT%H:%M:%SZ")
        localDateTime = dateTime[1]
        logging.debug("%s | %s | %s | %s", gpxFile, date_time.text, zuluDateTime, localDateTime)
        logging.debug("<<")
        return (zuluDateTime, localDateTime) class EquipmentService(object):
   
   """Provides access to stored equipment items."""
   
   def __init__(self, ddbb):
       self._ddbb = ddbb
       
   def get_all_equipment(self):
       """Get all equipment items."""
       return self._ddbb.session.query(Equipment).all()
   
   def get_active_equipment(self):
       """Get all the active equipment items."""
       return self._ddbb.session.query(Equipment).filter(Equipment.active == True).all()
   
   def get_equipment_item(self, item_id):
       """Get an individual equipment item by id.
       
       If no item with the given id exists then None is returned.
       """
       try:
           return self._ddbb.session.query(Equipment).filter(Equipment.id == item_id).one()
       except exc.NoResultFound:
           return None
       
   def store_equipment(self, equipment):
       """Store a new or update an existing equipment item.
       
       The stored object is returned."""
       logging.debug("Storing equipment item.")
       try:
          self._ddbb.session.add(equipment)
          self._ddbb.session.commit()
       except IntegrityError:
          raise EquipmentServiceException("An equipment item already exists with description '{0}'".format(equipment.description))
       return equipment

   def remove_equipment(self, equipment):
       """Remove an existing equipment item."""
       logging.debug("Deleting equipment item with id: '{0}'".format(equipment.id))
       self._ddbb.session.delete(equipment)
       self._ddbb.session.commit()
   
   def get_equipment_usage(self, equipment):
       """Get the total use of the given equipment."""
       result = self._ddbb.session.query(func.sum(Activity.distance).label('sum')).filter(Activity.equipment.contains(equipment))
       usage = result.scalar()
       return (0 if usage == None else float(usage)) + equipment.prior_usage class Equipment(DeclarativeBase):
   """An equipment item that can be used during an activity, such as a pair of running shoes."""

   __tablename__ = 'equipment'
   active = Column(Boolean)
   description = Column(Unicode(length=100), unique=True, index=True)
   id = Column(Integer, primary_key=True)
   life_expectancy = Column(ForcedInteger)
   notes = Column(UnicodeText)
   prior_usage = Column(ForcedInteger)

   def __init__(self, **kwargs):
       self.description = u""
       self.active = True
       self.life_expectancy = 0
       self.prior_usage = 0
       self.notes = u""
       super(Equipment, self).__init__(**kwargs)

   def __eq__(self, o):
       if isinstance(o, Equipment):
           if self.id is not None and o.id is not None:
               return self.id == o.id
       return False
       
   def __hash__(self):
       if self.id is not None:
           return self.id
       else:
           return object.__hash__(self) class Sport(DeclarativeBase):
    """A type of exercise. For example: "running" or "cycling"."""
    __tablename__ = 'sports'
    color = Column(ColorType(length=6), nullable=False)
    id = Column('id_sports', Integer, primary_key=True, nullable=False)
    max_pace = Column(ForcedInteger, CheckConstraint('max_pace>=0'))
    met = Column(Float, CheckConstraint('met>=0'))
    name = Column(Unicode(length=100), nullable=False, unique=True, index=True)
    weight = Column(Float, CheckConstraint('weight>=0'), nullable=False)

    def __init__(self, **kwargs):
        self.name = u""
        self.weight = 0.0
        self.met = None
        self.max_pace = None
        self.color = Color(0x0000ff)
        super(Sport, self).__init__(**kwargs) class Activity(DeclarativeBase):
    '''
    Class that knows everything about a particular activity

    All values are stored in the class (and DB) in metric and are converted as needed

    tracks                  - (list) tracklist from gpx
    tracklist               - (list of dict) trackpoint data from gpx
    laps                    - (list of dict) lap list
    us_system               - (bool) True: imperial measurement False: metric measurement
    distance_data   - (dict of graphdata classes) contains the graph data with x axis distance
    time_data               - (dict of graphdata classes) contains the graph data with x axis time
    gpx_file                - (string) gpx file name
    gpx                             - (Gpx class) actual gpx instance
    sport_name              - (string) sport name
    sport_id                - (string) id for sport in sports table
    title                   - (string) title of activity
    date                    - (string) date of activity
    time                    - (int) activity duration in seconds
    time_tuple              - (tuple) activity duration as hours, min, secs tuple
    beats                   - (int) average heartrate for activity
    maxbeats                - (int) maximum heartrate for activity
    comments                - (string) activity comments
    calories                - (int) calories of activity
    id                      - (int) id for activity in records table
    date_time_local - (string) date and time of activity in local timezone
    date_time_utc   - (string) date and time of activity in UTC timezone
    date_time               - (datetime) date and time of activity in local timezone
    starttime               - (string)
    distance                - (float) activity distance
    average                 - (float) average speed of activity
    upositive               - (float) height climbed during activity
    unegative               - (float) height decended during activity
    maxspeed                - (float) maximum speed obtained during activity
    maxpace                 - (float) maxium pace obtained during activity
    pace                    - (float) average pace for activity
    has_data                - (bool) true if instance has data populated
    x_axis                  - (string) distance or time, determines what will be graphed on x axis
    x_limits                - (tuple of float) start, end limits of x axis (as determined by matplotlib)
    y1_limits               - (tuple of float) start, end limits of y1 axis (as determined by matplotlib)
    y2_limits               - (tuple of float) start, end limits of y2 axis (as determined by matplotlib)
    x_limits_u              - (tuple of float) start, end limits of x axis (as requested by user)
    y1_limits_u             - (tuple of float) start, end limits of y1 axis (as requested by user)
    y2_limits_u             - (tuple of float) start, end limits of y2 axis (as requested by user)
    show_laps               - (bool) display laps on graphs
    lap_distance    - (graphdata)
    lap_time                - (graphdata)
    pace_limit              - (int) maximum pace that is valid for this activity
    '''
    __tablename__ = 'records'
    average = Column(Float)
    beats = Column(Float)
    calories = Column(ForcedInteger)
    comments = Column(UnicodeText)
    date = Column(Date)
    date_time_local = Column(String(length=40))
    date_time_utc = Column(String(length=40))
    distance = Column(Float)
    duration = Column(ForcedInteger)
    gpslog = deferred(Column(String(length=200)))
    id = Column("id_record", Integer, primary_key=True)
    maxbeats = Column(Float)
    maxpace = Column(Float)
    maxspeed = Column(Float)
    pace = Column(Float)
    sport_id = Column("sport", Integer, ForeignKey('sports.id_sports'),
                          index=True, nullable=False)
    title = Column(Unicode(length=200))
    unegative = Column(Float)
    upositive = Column(Float)

    #relation definitions
    sport = relationship("Sport", backref=backref("activities", order_by=date,
                                                  cascade='all, delete-orphan'))
    equipment = relationship("Equipment", secondary=record_to_equipment,
                             backref=backref("activities", order_by=date))
    Laps = relationship('Lap', backref=backref('activity'),
                        order_by='Lap.lap_number',
                        cascade='all, delete-orphan')

    def __init__(self, **kwargs):
        self._initialize()
        super(Activity, self).__init__(**kwargs)

    @reconstructor
    def _initialize(self):
        logging.debug(">>")
        self.environment = Environment()
        self.uc = uc.UC()
        self.profile = Profile()
        self.has_data = True
        self._distance_data = {}
        self._time_data = {}
        self._lap_time = None
        self._lap_distance = None
        self.time_pause = 0
        self.pace_limit = None
        self._gpx = None
        self.x_axis = "distance"
        self.x_limits = (None, None)
        self.y1_limits = (None, None)
        self.y2_limits = (None, None)
        self.x_limits_u = (None, None)
        self.y1_limits_u = (None, None)
        self.y2_limits_u = (None, None)
        self.y1_grid = False
        self.y2_grid = False
        self.x_grid = False
        self.show_laps = False
        logging.debug("<<")

    @property
    def gpx_file(self):
        if self.id:
            filename = "%s/%s.gpx" % (self.environment.gpx_dir, self.id)
            #It is OK to not have a GPX file for an activity - this just limits us to information in the DB
            if os.path.isfile(filename):
                return filename
        logging.debug("No GPX file found for record id: %s", self.id)
        return None

    @property
    def tracks(self):
        if self.gpx:
            return self.gpx.getTrackList()
        else:
            return None

    @property
    def tracklist(self):
        if self.gpx:
            return self.gpx.trkpoints
        else:
            return None

    @property
    def distance_data(self):
        if not self._distance_data:
            self._init_graph_data()
        return self._distance_data

    @property
    def time_data(self):
        if not self._time_data:
            self._init_graph_data()
        return self._time_data

    @property
    def lap_time(self):
        if not self._lap_time:
            self._generate_per_lap_graphs()
        return self._lap_time

    @property
    def lap_distance(self):
        if not self._lap_distance:
            self._generate_per_lap_graphs()
        return self._lap_distance

    @property
    def time_tuple(self):
        return second2time(self.duration)

    @property
    def date_time(self):
        if self.date_time_local: #Have a local time stored in DB
            return dateutil.parser.parse(self.date_time_local)
        else: #No local time in DB
            #datetime with localtime offset (using value from OS)
            return dateutil.parser.parse(self.date_time_utc).astimezone(tzlocal())

    @property
    def starttime(self):
        return self.date_time.strftime("%X")

    @property
    def laps(self):
        warnings.warn("Deprecated property Activity.laps called", DeprecationWarning, stacklevel=2)
        ret = []
        for lap in self.Laps:
            d = dict(lap.__dict__)
            d.pop('_sa_instance_state', None)
            ret.append(d)
        return ret

    def __str__(self):
        return '''
tracks (%s)
        tracklist (%s)
        laps (%s)
        us_system (%s)
        distance_data (%s)
        time_data (%s)
        gpx_file (%s)
        gpx (%s)
        sport_name (%s)
        sport_id (%s)
        title (%s)
        date (%s)
        time (%s)
        time_tuple (%s)
        beats (%s)
        maxbeats (%s)
        comments (%s)
        calories (%s)
        id (%s)
        date_time_local (%s)
        date_time_utc (%s)
        date_time (%s)
        starttime (%s)
        distance (%s)
        average (%s)
        upositive (%s)
        unegative (%s)
        maxspeed (%s)
        maxpace (%s)
        pace (%s)
        has_data (%s)
        x_axis (%s)
        x_limits (%s)
        y1_limits (%s)
        y2_limits (%s)
        x_limits_u (%s)
        y1_limits_u (%s)
        y2_limits_u (%s)
        show_laps (%s)
        lap_distance (%s)
        lap_time (%s)
        pace_limit (%s)
''' % ('self.tracks', self.tracklist, self.laps, self.uc.us,
                self.distance_data, self.time_data,
                self.gpx_file, self.gpx, self.sport_name,
                self.sport_id, self.title, self.date, self.duration, self.time_tuple, self.beats,
                self.maxbeats, self.comments, self.calories, self.id, self.date_time_local,
                self.date_time_utc, self.date_time, self.starttime, self.distance, self.average,
                self.upositive, self.unegative, self.maxspeed, self.maxpace, self.pace, self.has_data,
                self.x_axis, self.x_limits, self.y1_limits, self.y2_limits, self.x_limits_u, self.y1_limits_u,
                self.y2_limits_u, self.show_laps, self.lap_distance, self.lap_time, self.pace_limit)

    @property
    def gpx(self):
        '''
        Get activity information from the GPX file
        '''
        logging.debug(">>")
        if self._gpx:
            logging.debug("Return pre-created GPX")
            return self._gpx
        elif self.gpx_file:
            logging.debug("Parse GPX")
            #Parse GPX file
            #print "Activity initing GPX.. ",
            self._gpx = Gpx(filename=self.gpx_file) #TODO change GPX code to do less....
            logging.info("GPX Distance: %s | distance (trkpts): %s | duration: %s | duration (trkpts): %s",
                         self.gpx.total_dist, self.gpx.total_dist_trkpts, self.gpx.total_time,
                         self.gpx.total_time_trkpts)
            time_diff = self.gpx.total_time_trkpts - self.gpx.total_time
            acceptable_lapse = 4 # number of seconds that duration calculated using lap and trkpts data can differ
            if time_diff > acceptable_lapse:
                self.time_pause = time_diff
                logging.debug("Identified non active time: %s s", self.time_pause)
            return self._gpx
        else:
            logging.debug("No GPX file found")
            return None
        logging.debug("<<")

    @property
    def time(self):
        warnings.warn("Deprecated property Activity.time called", DeprecationWarning, stacklevel=2)
        return self.duration

    @property
    def sport_name(self):
        warnings.warn("Deprecated property Activity.sport_name called", DeprecationWarning, stacklevel=2)
        return self.sport.name

    def _generate_per_lap_graphs(self):
        '''Build lap based graphs...'''
        logging.debug(">>")
        if self.laps is None:
            logging.debug("No laps to generate graphs from")
            logging.debug("<<")
            return
        #Lap columns
        self._lap_distance = GraphData()
        self._lap_distance.set_color('#CCFF00', '#CCFF00')
        self._lap_distance.graphType = "vspan"
        self._lap_time = GraphData()
        self._lap_time.set_color('#CCFF00', '#CCFF00')
        self._lap_time.graphType = "vspan"
        #Pace
        title = _("Pace by Lap")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Pace'), self.uc.unit_pace)
        self.distance_data['pace_lap'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self.distance_data['pace_lap'].set_color('#99CCFF', '#99CCFF')
        self.distance_data['pace_lap'].graphType = "bar"
        xlabel=_("Time (seconds)")
        self.time_data['pace_lap'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self.time_data['pace_lap'].set_color('#99CCFF', '#99CCFF')
        self.time_data['pace_lap'].graphType = "bar"
        #Speed
        title = _("Speed by Lap")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Speed'), self.uc.unit_speed)
        self.distance_data['speed_lap'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self.distance_data['speed_lap'].set_color('#336633', '#336633')
        self.distance_data['speed_lap'].graphType = "bar"
        xlabel = _("Time (seconds)")
        self.time_data['speed_lap'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self.time_data['speed_lap'].set_color('#336633', '#336633')
        self.time_data['speed_lap'].graphType = "bar"
        for lap in self.laps:
            time = float(lap['elapsed_time']) # time in sql is a unicode string
            dist = lap['distance']/1000 #distance in km
            try:
                pace = time/(60*dist) #min/km
            except ZeroDivisionError:
                pace = 0.0
            try:
                avg_speed = dist/(time/3600) # km/hr
            except:
                avg_speed = 0.0
            if self.pace_limit is not None and pace > self.pace_limit:
                logging.debug("Pace (%s) exceeds limit (%s). Setting to 0", pace, self.pace_limit)
                pace = 0.0
            logging.debug("Time: %f, Dist: %f, Pace: %f, Speed: %f", time, dist, pace, avg_speed)
            self._lap_time.addBars(x=time, y=10)
            self._lap_distance.addBars(x=self.uc.distance(dist), y=10)
            self.distance_data['pace_lap'].addBars(x=self.uc.distance(dist), y=self.uc.distance(pace))
            self.time_data['pace_lap'].addBars(x=time, y=self.uc.speed(pace))
            self.distance_data['speed_lap'].addBars(x=self.uc.distance(dist), y=self.uc.speed(avg_speed))
            self.time_data['speed_lap'].addBars(x=time, y=self.uc.speed(avg_speed))
        logging.debug("<<")

    def _init_graph_data(self):
        logging.debug(">>")
        if self.tracklist is None:
            logging.debug("No tracklist in activity")
            logging.debug("<<")
            return
        #Profile
        title = _("Elevation")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Elevation'), self.uc.unit_height)
        self._distance_data['elevation'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['elevation'].set_color('#ff0000', '#ff0000')
        self._distance_data['elevation'].show_on_y1 = True #Make graph show elevation by default
        xlabel = _("Time (seconds)")
        self._time_data['elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel)
        self._time_data['elevation'].set_color('#ff0000', '#ff0000')
        self._time_data['elevation'].show_on_y1 = True #Make graph show elevation by default
        #Corrected Elevation...
        title = _("Corrected Elevation")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Corrected Elevation'), self.uc.unit_height)
        self._distance_data['cor_elevation'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['cor_elevation'].set_color('#993333', '#993333')
        xlabel=_("Time (seconds)")
        self._time_data['cor_elevation'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel)
        self._time_data['cor_elevation'].set_color('#993333', '#993333')
        #Speed
        title = _("Speed")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Speed'), self.uc.unit_speed)
        self._distance_data['speed'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['speed'].set_color('#000000', '#000000')
        xlabel = _("Time (seconds)")
        self._time_data['speed'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel)
        self._time_data['speed'].set_color('#000000', '#000000')
        #Pace
        title = _("Pace")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Pace'), self.uc.unit_pace)
        self._distance_data['pace'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['pace'].set_color('#0000ff', '#0000ff')
        xlabel = _("Time (seconds)")
        self._time_data['pace'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel)
        self._time_data['pace'].set_color('#0000ff', '#0000ff')
        #Heartrate
        title = _("Heart Rate")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Heart Rate'), _('bpm'))
        self._distance_data['hr'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['hr'].set_color('#00ff00', '#00ff00')
        xlabel = _("Time (seconds)")
        self._time_data['hr'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel)
        self._time_data['hr'].set_color('#00ff00', '#00ff00')
        #Heartrate as %
        maxhr = self.profile.getMaxHR()
        title = _("Heart Rate (% of max)")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Heart Rate'), _('%'))
        self._distance_data['hr_p'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['hr_p'].set_color('#00ff00', '#00ff00')
        xlabel = _("Time (seconds)")
        self._time_data['hr_p'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._time_data['hr_p'].set_color('#00ff00', '#00ff00')
        #Cadence
        title = _("Cadence")
        xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
        ylabel = "%s (%s)" % (_('Cadence'), _('rpm'))
        self._distance_data['cadence'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._distance_data['cadence'].set_color('#cc00ff', '#cc00ff')
        xlabel = _("Time (seconds)")
        self._time_data['cadence'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
        self._time_data['cadence'].set_color('#cc00ff', '#cc00ff')
        for track in self.tracklist:
            try:
                pace = 60/track['velocity']
                if self.pace_limit is not None and pace > self.pace_limit:
                    logging.debug("Pace (%s) exceeds limit (%s). Setting to 0", pace, self.pace_limit)
                    pace = 0  #TODO this should be None when we move to newgraph...
            except Exception as e:
                #print type(e), e
                pace = 0
            try:
                hr_p = float(track['hr'])/maxhr*100
            except:
                hr_p = 0
            self._distance_data['elevation'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                       y=self.uc.height(track['ele']))
            self._distance_data['cor_elevation'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                           y=self.uc.height(track['correctedElevation']))
            self._distance_data['speed'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                   y=self.uc.speed(track['velocity']))
            self._distance_data['pace'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                  y=self.uc.distance(pace))
            self._distance_data['hr'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                y=track['hr'])
            self._distance_data['hr_p'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                  y=hr_p)
            self._distance_data['cadence'].addPoints(x=self.uc.distance(track['elapsed_distance']),
                                                     y=track['cadence'])
            self._time_data['elevation'].addPoints(x=track['time_elapsed'],
                                                   y=self.uc.height(track['ele']))
            self._time_data['cor_elevation'].addPoints(x=track['time_elapsed'],
                                                       y=self.uc.height(track['correctedElevation']))
            self._time_data['speed'].addPoints(x=track['time_elapsed'],
                                               y=self.uc.speed(track['velocity']))
            self._time_data['pace'].addPoints(x=track['time_elapsed'],
                                              y=self.uc.distance(pace))
            self._time_data['hr'].addPoints(x=track['time_elapsed'], y=track['hr'])
            self._time_data['hr_p'].addPoints(x=track['time_elapsed'], y=hr_p)
            self._time_data['cadence'].addPoints(x=track['time_elapsed'], y=track['cadence'])
        #Remove data with no values
        for item in list(self._distance_data.keys()):
            if len(self._distance_data[item]) == 0:
                logging.debug("No values for %s. Removing....", item)
                del self._distance_data[item]
        for item in list(self._time_data.keys()):
            if len(self._time_data[item]) == 0:
                logging.debug("No values for %s. Removing....", item)
                del self._time_data[item]
        logging.debug("<<")
        #Add Heartrate zones graphs
        if 'hr' in self._distance_data:
            zones = self.profile.getZones()
            title = _("Heart Rate zone")
            xlabel = "%s (%s)" % (_('Distance'), self.uc.unit_distance)
            ylabel = "%s (%s)" % (_('Heart Rate'), _('bpm'))
            self._distance_data['hr_z'] = GraphData(title=title, xlabel=xlabel, ylabel=ylabel)
            self._distance_data['hr_z'].graphType = "hspan"
            self._distance_data['hr_z'].set_color(None, None)
            xlabel = _("Time (seconds)")
            self._time_data['hr_z'] = GraphData(title=title,xlabel=xlabel, ylabel=ylabel)
            self._time_data['hr_z'].set_color(None, None)
            for zone in zones:
                self._distance_data['hr_z'].addPoints(x=zone[0], y=zone[1], label=zone[3], color=zone[2])
                self._time_data['hr_z'].addPoints(x=zone[0], y=zone[1], label=zone[3], color=zone[2])

    def _float(self, value):
        try:
            result = float(value)
        except:
            result = 0.0
        return result

    def _int(self, value):
        try:
            result = int(value)
        except:
            result = 0
        return result

    def get_value_f(self, param, format=None):
        ''' Function to return a value formated as a string
                - takes into account US/metric
                - also appends units if required
        '''
        value = self.get_value(param)
        if not value:
            #Return blank string if value is None or 0
            return ""
        if format is not None:
            result = format % value
        else:
            result = str(value)
        return result

    def get_value(self, param):
        ''' Function to get the value of various params in this activity instance
                Automatically returns values converted to imperial if needed
        '''
        if param == 'distance':
            return self.uc.distance(self.distance)
        elif param == 'average':
            return self.uc.speed(self.average)
        elif param == 'upositive':
            return self.uc.height(self.upositive)
        elif param == 'unegative':
            return self.uc.height(self.unegative)
        elif param == 'maxspeed':
            return self.uc.speed(self.maxspeed)
        elif param == 'maxpace':
            return uc.float2pace(self.uc.pace(uc.pace_from_db(self.maxpace)))
        elif param == 'pace':
            return uc.float2pace(self.uc.pace(uc.pace_from_db(self.pace)))
        elif param == 'calories':
            return self.calories
        elif param == 'time':
            if not self.duration:
                return ""
            _hour ,_min, _sec = second2time(self.duration)
            if _hour == 0:
                return "%02d:%02d" % (_min, _sec)
            else:
                return "%0d:%02d:%02d" % (_hour, _min, _sec)
        else:
            logging.error("Unable to provide value for unknown parameter (%s) for activity", param)
            return None class Lap(DeclarativeBase):
    __tablename__ = 'laps'
    avg_hr = Column(ForcedInteger)
    calories = Column(ForcedInteger)
    comments = Column(UnicodeText)
    distance = Column(Float)
    elapsed_time = Column(String(length=20))
    end_lat = Column(Float)
    end_lon = Column(Float)
    id_lap = Column(Integer, primary_key=True)
    intensity = Column(String(length=7))
    lap_number = Column(ForcedInteger)
    laptrigger = Column(String(length=9))
    max_hr = Column(ForcedInteger)
    max_speed = Column(Float)
    record = Column(Integer, ForeignKey('records.id_record'), index=True, nullable=False)
    start_lat = Column(Float)
    start_lon = Column(Float)

    @property
    def duration(self):
        return float(self.elapsed_time) class DateRange(object):

    """A date range consisting of a start date and an end date."""

    def __init__(self, start_date, end_date):
        if not isinstance(start_date, datetime.date):
            raise TypeError("Start date must be datetime.date, not {0}.".format(type(start_date).__name__))
        if not isinstance(end_date, datetime.date):
            raise TypeError("End date must be datetime.date, not {0}.".format(type(start_date).__name__))
        if start_date > end_date:
            raise ValueError("End date cannot be before start date.")
        self._start_date = start_date
        self._end_date = end_date

    @property
    def start_date(self):
        return self._start_date

    @property
    def end_date(self):
        return self._end_date

    def __str__(self):
        fmt = "%Y%m%d"
        return self._start_date.strftime(fmt) + "-" + self._end_date.strftime(fmt)

    @classmethod
    def for_week_containing(clazz, date):
        """Get the date range for the week containing the given date.

        The date range will start on the first day of the week and end on the
        last day of the week. The week start and end days are locale dependent.

        Args:
            date (datetime.date): a date within the week to get the date range for.
        Returns:
            (DateRange): the date range for a week.
        """
        day_of_week = (int(date.strftime("%w")) - get_platform().get_first_day_of_week()) % 7
        date_start = date + datetime.timedelta(days = 0 - day_of_week)
        date_end = date + datetime.timedelta(days = 6 - day_of_week)
        return DateRange(date_start, date_end)

    @classmethod
    def for_month_containing(clazz, date):
        """Get the date range for the month containing the given date.

        The date range will start on the first day of the month and end on the
        last day of the month.

        Args:
            date (datetime.date): a date within the month to get the date range for.
        Returns:
            (DateRange): the date range for a month.
        """
        date_start = datetime.date(date.year, date.month, 1)
        next_month = date.month + 1
        next_month_year = date.year
        if (next_month == 13):
            next_month = 1
            next_month_year += 1
        date_end = datetime.date(next_month_year, next_month, 1) - datetime.timedelta(days=1)
        return DateRange(date_start, date_end)

    @classmethod
    def for_year_containing(clazz, date):
        """Get the date range for the year containing the given date.

        The date range will start on the first day of the year and end on the
        last day of the year.

        Args:
            date (datetime.date): a date within the year to get the date range for.
        Returns:
            (DateRange): the date range for a year.
        """
        date_start = datetime.date(date.year, 1, 1)
        date_end = datetime.date(date.year, 12, 31)
        return DateRange(date_start, date_end)
import os
import shutil
import logging
import datetime
import warnings
from sqlalchemy.orm.exc import NoResultFound
from .gui.windowrecord import WindowRecord
from .gui.dialogselecttrack import DialogSelectTrack
from .lib.date import Date, time2second
from .lib.gpx import Gpx
from pytrainer.core.equipment import EquipmentService, Equipment
from pytrainer.core.sport import Sport
from pytrainer.core.activity import Activity, Lap
from pytrainer.lib.date import DateRange
            from .gui.warning import Warning
# -*- coding: utf-8 -*-

#Copyright (C) Fiz Vazquez vud1@sindominio.net
#Modified by dgranda

#This program 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, write to the Free Software
#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.




class Record:
    def __init__(self, sport_service, data_path = None, parent = None):
        logging.debug('>>')
        self._sport_service = sport_service
        self.parent = parent
        self.pytrainer_main = parent
        self._equipment_service = EquipmentService(self.pytrainer_main.ddbb)
        self.data_path = data_path
        logging.debug('setting date...')
        self.date = Date()
        logging.debug('<<')

    def newRecord(self, date, title=None, distance=None, time=None, upositive=None, unegative=None, bpm=None, calories=None, comment=None):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()

        self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, self, self.format_date(date), title, distance, time, upositive, unegative, bpm, calories, comment)