def getBasicDemographicInformation(self):
        tree = self.getThings('bf516a61-5252-4c28-a979-27f45f62f78d')

        for id in [t.text for t in csss('thing-id')(tree)]:
            tree = self.getThingById(id)
            self.person.gender = csss('gender')(tree)[0].text
            self.person.birth_year = csss('birthyear')(tree)[0].text
    def _authenticate(self):
        content_tmpl = string.Template("""
            <content>
                <app-id>$APP_ID</app-id>
                <hmac>HMACSHA256</hmac>
                <signing-time>$NOW</signing-time>
            </content>
        """)

        content_str = content_tmpl.substitute({
            'APP_ID': settings.APP_ID,
            'NOW': self._now_in_iso()
        }).translate(None, '\n ')

        t = string.Template("""
        <wc-request:request xmlns:wc-request="urn:com.microsoft.wc.request">
            <header>
                <method>CreateAuthenticatedSessionToken</method>
                <method-version>2</method-version>
                <app-id>$APP_ID</app-id>
                <msg-time>$NOW</msg-time>
                <msg-ttl>$MSG_TTL</msg-ttl>
                <version>$VERSION</version>
            </header>
            <info>
                <auth-info>
                    <app-id>$APP_ID</app-id>
                    <credential>
                        <appserver2>
                            <sig digestMethod="SHA1"
                                 sigMethod="RSA-SHA1"
                                 thumbprint="$APP_THUMBPRINT">
                                    $SIGNATURE
                            </sig>
                            $CONTENT
                        </appserver2>
                    </credential>
                </auth-info>
            </info>
        </wc-request:request>""")

        payload = t.substitute({
            'APP_ID': settings.APP_ID,
            'NOW': self._now_in_iso(),
            'MSG_TTL': self._ttl,
            'VERSION': self._version,
            'APP_THUMBPRINT': settings.APP_THUMBPRINT,
            'SIGNATURE': self._sign(content_str),
            'CONTENT': content_str

        }).translate(None, '\n')

        tree = self._send_request_and_get_tree(payload)
        self._auth_token = csss('token')(tree)[0].text
        self._shared_secret = csss('shared-secret')(tree)[0].text
    def getAuthorizedConnectRequests(self):
        tree = self._send_request_and_get_tree(
            self._create_request('<info></info>',
                                 'GetAuthorizedConnectRequests')
        )

        reqs = []
        for e in csss('connect-request')(tree):
            person_id = csss('person-id')(e)[0].text
            record_id = csss('record-id')(e)[0].text
            external_id = csss('external-id')(e)[0].text
            reqs.append((person_id, record_id, external_id))
        return reqs
class HVConn(object):
    _user_auth_token = None
    _offline_person_id = None
    _auth_token = None
    _record_id = None
    _app_specific_record_id = None
    _shared_secret = None
    _private_key = None
    _version = '2.0.0.0'
    _language = 'en'
    _country = 'US'
    _ttl = '1800'

    person = HVPerson()

    def _now_in_iso(self):
        return datetime.datetime.utcnow().isoformat()

    def _init_private_key(self):
        self._private_key = RSA.construct((
            long(settings.APP_PUBLIC_KEY, 16),
            long(65537),
            long(settings.APP_PRIVATE_KEY, 16)
        ))

    def _sign(self, data):
        signer = PKCS1_v1_5.new(self._private_key)
        return base64.encodestring(signer.sign(SHA.new(data)))

    def _send_request(self, payload):
        pass

    def _send_request_and_get_tree(self, payload):
        conn = httplib.HTTPSConnection(settings.HV_SERVICE_SERVER, 443)
        conn.putrequest('POST', '/platform/wildcat.ashx')
        conn.putheader('Content-Type', 'text/xml')
        conn.putheader('Content-Length', '%d' % len(payload))
        conn.endheaders()
        logging.debug('\nsending:\n'+payload)

        try:
            conn.send(payload)
        except socket.error, v:
            if v[0] == 32:      # Broken pipe
                conn.close()
            raise
        resp = conn.getresponse()
        if resp.status != 200:
            raise
        else:
            tree = etree.fromstring(resp.read())
            logging.debug('\ngot:\n'+etree.tostring(tree, pretty_print=True))

            if csss('code')(tree)[0].text != '0':
                # FIXME: the re-auth case
                raise ('_send_request_and_get_tree: non-zero return code '
                       'Re-auth may be required.')
            else:
                return tree
    def getGlucoseMeasurements(self):
        tree = self.getThings('879e7c04-4e8a-4707-9ad3-b054df467ce4')
        self.person.glucoses = []

        for thing in csss('thing')(tree):
            date = csss('date')(thing)[0]
            time = csss('time')(thing)[0]
            y = int(csss('y')(date)[0].text)
            m = int(csss('m')(date)[0].text)
            d = int(csss('d')(date)[0].text)
            h = int(csss('h')(time)[0].text)
            min = int(csss('m')(time)[0].text)
            s = int(csss('s')(time)[0].text)

            dt = datetime.datetime(y, m, d, h, min, s).isoformat()
            g = float(csss('mmolPerL')(thing)[0].text)
            self.person.glucoses.append((dt, round(g, 2)))
    def getWeightMeasurements(self):
        tree = self.getThings('3d34d87e-7fc1-4153-800f-f56592cb0d17')
        self.person.weights = []  # clear weights

        for id in [t.text for t in csss('thing-id')(tree)]:
            tree = self.getThingById(id)
            date = csss('date')(tree)[0]
            time = csss('time')(tree)[0]
            y = int(csss('y')(date)[0].text)
            m = int(csss('m')(date)[0].text)
            d = int(csss('d')(date)[0].text)
            h = int(csss('h')(time)[0].text)
            min = int(csss('m')(time)[0].text)
            s = int(csss('s')(time)[0].text)

            dt = datetime.datetime(y, m, d, h, min, s).isoformat()
            weight_in_kg = float(csss('kg')(tree)[0].text)
            self.person.weights.append((dt, round(weight_in_kg, 2)))
    def getPersonInfo(self):
        # TODO: extract more record data
        # <record app-record-auth-action="NoActionRequired"
        # app-specific-record-id="218697"
        # auth-expires="9999-12-31T23:59:59.999Z"
        # date-created="2012-09-19T16:07:52.507Z"
        # date-updated="2012-09-24T19:22:00.877Z" display-name="Arjun"
        # id="f9982b79-4369-4357-8268-0b344941ab02" location-country="US"
        # max-size-bytes="4294967296" record-custodian="true" rel-name="Self"
        # rel-type="1" size-bytes="3167" state="Active">

        tree = self._send_request_and_get_tree(
            self._create_request('<info></info>', 'GetPersonInfo')
        )
        self.person.person_id = csss('person-id')(tree)[0].text
        self.person.name = csss('name')(tree)[0].text
        self.person.selected_record_id = \
            csss('selected-record-id')(tree)[0].text
        self._record_id = self.person.selected_record_id
    def createConnectRequest(self,
                             external_id,
                             friendly_name,
                             secret_q,
                             secret_a):
        info_tmpl = string.Template(
            '<info>'
            '<friendly-name>$FRIENDLY_NAME</friendly-name>'
            '<question>$QUESTION</question>'
            '<answer>$ANSWER</answer>'
            '<external-id>$EXTERNAL_ID</external-id>'
            '</info>')
        info = info_tmpl.substitute({
            'FRIENDLY_NAME': friendly_name,
            'QUESTION': secret_q,
            'ANSWER': secret_a,
            'EXTERNAL_ID': external_id
        })

        tree = self._send_request_and_get_tree(
            self._create_request(info, 'CreateConnectRequest')
        )
        return csss('identity-code')(tree)[0].text