code:
<!-- Copyright 2008-2010 StatusNet Inc. and contributors. -->
<!-- Document licensed under Creative Commons Attribution 3.0 Unported. See -->
<!-- https://creativecommons.org/licenses/by/3.0/ for details. -->

%%site.name%% supports
[tags](https://en.wikipedia.org/wiki/Tag_(metadata)) to help you
organize your activities here. You can use tags for people and for
notices.

Tagging a notice
----------------

You can tag a notice using a *hashtag*; a # character followed by
letters and numbers as well as '.', '-', and '_'. Note that accented
latin characters are not supported, and non-roman scripts are right out.

The HTML for the notice will link to a stream of all the other notices
with that tag. This can be a great way to keep track of a conversation.

Tagging yourself
----------------

You can also add tags for yourself on your [profile
settings](%%action.profilesettings%%) page or by using the edit tags
button on your profile page. Use single words to
describe yourself, your experiences and your interest. The tags will
become links on your profile page to a list of all the users on the
site who use that same tag. It can be a nice way to find people who
are related to you geographically or who have a common interest.

Tagging others
--------------

You can also tag other users by using the edit tags button next to
their profile. Such tags are called *people tags*. Once you have
created a people tag, you can add or remove users from it using the
tag's edit form. This makes it easy to organize your subscriptions
into groups and sort through them separately. Also, it will let
you create custom lists of people that others can subscribe to.

You can also send a notice "to the attention of" your subscribers
whom you've marked with a particular tag (note: *not* people who've
marked themselves with that tag). "@#family hello" will send a
notice to all your subscribers you've marked with the tag 'family'.

Private and public people tags
------------------------------

A private people tag is only visible to the creator, it cannot be
subscribed to, but the timeline can be viewed. To create a new
private prepend a '.' to the tag in the tags editing box. To set
an existing public tag as private or vice-versa, go to the tag's
edit page.

path: doc-src/tags


code:
The gist
--------

We (the folks at [%%site.broughtby%%](%%site.broughtbyurl%%)) run a
service called %%site.name%% and would love for you to use it. Our
service is designed to give you as much control and ownership over
what goes in your notice stream as possible and encourage you to
express yourself freely. However, be responsible in what you post. In
particular, make sure that none of the prohibited items listed below
appear in your notice stream or get linked to from your notice stream (things
like spam, viruses, or hate content).

You can review our [Public Stream](%%action.top%%) to get a sense
of the types of notices that are welcome on our service (or not!). If
you find a %%site.name%% account that you believe violates our terms
of service, please check our [Contact](%%doc.contact%%) documentation.

(Note: Automattic, Inc., original creators of the below Terms of
Service, decided to make them available under a Creative Commons
Sharealike license, which means you’re more than welcome to steal it
and repurpose it for your own use. Just make sure to replace
references to us with ones to you. They’d appreciate a link to
[WordPress.com](https://wordpress.com/) somewhere on your site.
They spent a lot of money and time on the below, and other people
shouldn’t need to do the same. (We didn't!))

Terms of Service
----------------

The following terms and conditions govern all use of the %%site.name%%
website and all content, services and products available at or through
the website (taken together, the Website). The Website is owned and
operated by %%site.broughtby%% (“Operator”). The Website is offered
subject to your acceptance without modification of all of the terms
and conditions contained herein and all other operating rules,
policies (including, without limitation, Operator’s [Privacy
Policy](%%doc.privacy%%))
and procedures that may be published from time to time on this Site by
Operator (collectively, the “Agreement”).

Please read this Agreement carefully before accessing or using the
Website. By accessing or using any part of the web site, you agree to
become bound by the terms and conditions of this agreement. If you do
not agree to all the terms and conditions of this agreement, then you
may not access the Website or use any services. If these terms and
conditions are considered an offer by Operator, acceptance is
expressly limited to these terms. The Website is available only to
individuals who are at least 13 years old.

Your %%site.name%% Account and Site. If you
create a notice stream on the Website, you are responsible for
maintaining the security of your account and notice stream, and you
are fully responsible for all activities that occur under the account
and any other actions taken in connection with the notice stream. You
must not describe or assign keywords to your notice stream in a
misleading or unlawful manner, including in a manner intended to trade
on the name or reputation of others, and Operator may change or remove
any description or keyword that it considers inappropriate or
unlawful, or otherwise likely to cause Operator liability. You must
immediately notify Operator of any unauthorized uses of your notice
stream, your account or any other breaches of security. Operator will
not be liable for any acts or omissions by You, including any damages
of any kind incurred as a result of such acts or omissions.

Responsibility of Contributors. If you operate a
notice stream, comment on a notice stream, post material to the
Website, post links on the Website, or otherwise make (or allow any
third party to make) material available by means of the Website (any
such material, “Content”), You are entirely responsible for the
content of, and any harm resulting from, that Content. That is the
case regardless of whether the Content in question constitutes text,
graphics, an audio file, or computer software. By making Content
available, you represent and warrant that:

the downloading, copying and use of the Content will not infringe
the proprietary rights, including but not limited to the copyright,
patent, trademark or trade secret rights, of any third party;

if your employer has rights to intellectual property you create,
you have either (i) received permission from your employer to post or
make available the Content, including but not limited to any software,
or (ii) secured from your employer a waiver as to all rights in or to
the Content;

you have fully complied with any third-party licenses
relating to the Content, and have done all things necessary to
successfully pass through to end users any required terms;

the Content does not contain or install any viruses, worms, malware,
Trojan horses or other harmful or destructive content;

the Content is not spam, and does not contain unethical or
unwanted commercial content designed to drive traffic to third party
sites or boost the search engine rankings of third party sites, or to
further unlawful acts (such as phishing) or mislead recipients as to
the source of the material (such as spoofing);

if the Content is machine- or randomly-generated, it is for
purposes of direct entertainment, information and/or utility for you
or other users, and not for spam,

the Content is not libelous or defamatory (more info on
what that means), does not contain threats or incite violence towards
individuals or entities, and does not violate the privacy or publicity
rights of any third party;

your notice stream is not getting advertised via unwanted electronic
messages such as spam links on newsgroups, email lists, other notice streams
and web sites, and similar unsolicited promotional methods;

your notice stream is not named in a manner that misleads your
readers into thinking that you are another person or company. For
example, your notice stream’s URL or name is not the name of a person other
than yourself or company other than your own; and

you have, in the case of Content that includes computer code,
accurately categorized and/or described the type, nature, uses and
effects of the materials, whether requested to do so by Operator or
otherwise.

By submitting Content to Operator for inclusion on your Website, you
grant Operator a world-wide, royalty-free, and non-exclusive license
to reproduce, modify, adapt and publish the Content solely for the
purpose of displaying, distributing and promoting your notice
stream.

By submitting Content to Operator for inclusion on your Website,
you grant all readers the right to use, re-use, modify and/or
re-distribute the Content under the terms of the %%license.title%%.

If you delete Content, Operator will use reasonable efforts to remove it from
the Website, but you acknowledge that caching or references to the
Content may not be made immediately unavailable.

Without limiting any of those representations or warranties, Operator
has the right (though not the obligation) to, in Operator’s sole
discretion (i) refuse or remove any content that, in Operator’s
reasonable opinion, violates any Operator policy or is in any way
harmful or objectionable, or (ii) terminate or deny access to and use
of the Website to any individual or entity for any reason, in
Operator’s sole discretion.

Responsibility of Website Visitors. Operator has not reviewed,
and cannot review, all of the material, including computer software,
posted to the Website, and cannot therefore be responsible for that
material’s content, use or effects. By operating the Website,
Operator does not represent or imply that it endorses the material
there posted, or that it believes such material to be accurate, useful
or non-harmful. You are responsible for taking precautions as
necessary to protect yourself and your computer systems from viruses,
worms, Trojan horses, and other harmful or destructive content. The
Website may contain content that is offensive, indecent, or otherwise
objectionable, as well as content containing technical inaccuracies,
typographical mistakes, and other errors. The Website may also contain
material that violates the privacy or publicity rights, or infringes
the intellectual property and other proprietary rights, of third
parties, or the downloading, copying or use of which is subject to
additional terms and conditions, stated or unstated. Operator
disclaims any responsibility for any harm resulting from the use by
visitors of the Website, or from any downloading by those visitors of
content there posted.

Content Posted on Other Websites. We have not reviewed, and
cannot review, all of the material, including computer software, made
available through the websites and webpages to which %%site.name%%
links, and that link to %%site.name%%. Operator does not have any
control over those external websites and webpages, and is not
responsible for their contents or their use. By linking to a
external website or webpage, Operator does not represent or
imply that it endorses such website or webpage. You are responsible
for taking precautions as necessary to protect yourself and your
computer systems from viruses, worms, Trojan horses, and other harmful
or destructive content. Operator disclaims any responsibility for
any harm resulting from your use of external websites and
webpages.

Copyright Infringement and DMCA Policy. As Operator asks
others to respect its intellectual property rights, it respects the
intellectual property rights of others. If you believe that material
located on or linked to by %%site.name%% violates your copyright, you
are encouraged to notify Operator in accordance with Operator’s
Digital Millennium Copyright Act (”DMCA”) Policy. Operator will
respond to all such notices, including as required or appropriate by
removing the infringing material or disabling all links to the
infringing material. In the case of a visitor who may infringe or
repeatedly infringes the copyrights or other intellectual property
rights of Operator or others, Operator may, in its discretion,
terminate or deny access to and use of the Website. In the case of
such termination, Operator will have no obligation to provide a
refund of any amounts previously paid to Operator.

Intellectual Property. This Agreement does not
transfer from Operator to you any Operator or third party intellectual
property, and all right, title and interest in and to such property
will remain (as between the parties) solely with Operator.
%%site.name%%, the %%site.name%% logo, and all other trademarks,
service marks, graphics and logos used in connection with
%%site.name%%, or the Website are trademarks or registered trademarks
of Operator or Operator’s licensors. Other trademarks, service marks,
graphics and logos used in connection with the Website may be the
trademarks of other third parties. Your use of the Website grants you
no right or license to reproduce or otherwise use any Operator or
third-party trademarks.

Changes. Operator reserves the right, at its sole
discretion, to modify or replace any part of this Agreement. It is
your responsibility to check this Agreement periodically for changes.
Your continued use of or access to the Website following the posting
of any changes to this Agreement constitutes acceptance of those
changes. Operator may also, in the future, offer new services and/or
features through the Website (including, the release of new tools and
resources). Such new features and/or services shall be subject to the
terms and conditions of this Agreement.

Termination. Operator may terminate your access
to all or any part of the Website at any time, with or without cause,
with or without notice, effective immediately. If you wish to
terminate this Agreement or your %%site.name%% account (if you have
one), you may simply discontinue using the Website. All provisions of
this Agreement which by their nature should survive termination shall
survive termination, including, without limitation, ownership
provisions, warranty disclaimers, indemnity and limitations of
liability.

Disclaimer of Warranties. The Website is provided
“as is”. Operator and its suppliers and licensors hereby disclaim all
warranties of any kind, express or implied, including, without
limitation, the warranties of merchantability, fitness for a
particular purpose and non-infringement. Neither Operator nor its
suppliers and licensors, makes any warranty that the Website will be
error free or that access thereto will be continuous or uninterrupted.
If you’re actually reading this, here’s a treat. You understand that
you download from, or otherwise obtain content or services through,
the Website at your own discretion and risk.

Limitation of Liability. In no event will
Operator, or its suppliers or licensors, be liable with respect to any
subject matter of this agreement under any contract, negligence,
strict liability or other legal or equitable theory for: (i) any
special, incidental or consequential damages; (ii) the cost of
procurement or substitute products or services; (iii) for interruption
of use or loss or corruption of data; or (iv) for any amounts that
exceed the fees paid by you to Operator under this agreement during
the twelve (12) month period prior to the cause of action. Operator
shall have no liability for any failure or delay due to matters beyond
their reasonable control. The foregoing shall not apply to the extent
prohibited by applicable law.

General Representation and Warranty. You
represent and warrant that (i) your use of the Website will be in
strict accordance with the Operator Privacy Policy, with this
Agreement and with all applicable laws and regulations (including
without limitation any local laws or regulations in your country,
state, city, or other governmental area, regarding online conduct and
acceptable content, and including all applicable laws regarding the
transmission of technical data exported from the United States or the
country in which you reside) and (ii) your use of the Website will not
infringe or misappropriate the intellectual property rights of any
third party.

Indemnification. You agree to indemnify and hold
harmless Operator, its contractors, and its licensors, and their
respective directors, officers, employees and agents from and against
any and all claims and expenses, including attorneys’ fees, arising
out of your use of the Website, including but not limited to out of
your violation this Agreement.

Miscellaneous. This Agreement constitutes the
entire agreement between Operator and you concerning the subject
matter hereof, and they may only be modified by a written amendment
signed by an authorized executive of Operator, or by the posting by
Operator of a revised version. If any part of this Agreement is held
invalid or unenforceable, that part will be construed to reflect the
parties’ original intent, and the remaining portions will remain in
full force and effect. A waiver by either party of any term or
condition of this Agreement or any breach thereof, in any one
instance, will not waive such term or condition or any subsequent
breach thereof. You may assign your rights under this Agreement to any
party that consents to, and agrees to be bound by, its terms and
conditions; Operator may assign its rights under this Agreement
without condition. This Agreement will be binding upon and will inure
to the benefit of the parties, their successors and permitted
assigns.

*Originally published by Automattic, Inc. as the [WordPress.com Terms
of Service](https://en.wordpress.com/tos/) and made available by them
under the [Creative Commons Attribution-ShareAlike 3.0
License](https://creativecommons.org/licenses/by-sa/3.0/).
Modifications to remove reference to "VIP services", rename "blog" to
"notice stream", remove the choice-of-venue clause, and add variables
specific to instances of this software made by Control Yourself, Inc.
and made available under the terms of the same license.*

repo_name: ksuudilla/gnu

path: doc-src/tos

license: mit


code:
## Authentication

### HTTP Basic authentication

The API uses [HTTP Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication).
Note that this means that users with only an OpenID login cannot use the API; they have to add a
password to their account using the control panel on the site.

### OAuth authentication

OAuth 1.0a authentication for API resources is also supported. Generally, StatusNet's
UI and API are similar to Twitter's for OAuth applications (if you're new to OAuth
check out [Beginner’s Guide to OAuth](http://hueniverse.com/oauth/)).

To use OAuth, you'll need to register your client application via the web interface
and obtain a consumer key and secret. You can find the interface for application
registration at [%%action.oauthappssettings%%](%%action.oauthappssettings%%).

## JSONP callbacks

For API methods that return [JSON](https://en.wikipedia.org/wiki/JSON), an optional
JSONP-style callback parameter is supported. If supplied, the response will be in
JSONP format with a callback of the given name. To make it easier for clients to
handle error conditions, HTTP error codes are suppressed, and the errors will be
returned in the response body when using JSONP.

## Rate limiting

There is currently no rate-limiting.

## Gotchas

Some things to remember:

* %%site.name%% supports the
  [OStatus federation protocol](https://en.wikipedia.org/wiki/OStatus) (as well as
  [OpenMicroBlogging](https://en.wikipedia.org/wiki/OpenMicroBlogging) for backwards
  compatibility), so many notices and friends' profiles may come from other servers.
* User nicknames are unique, but they are not globally unique. Use the ID number
  instead.
* Private streams are not implemented yet.
* GNU social sites can be configured as private. In that case, all API methods
  require authentication, including the public timeline (see the 'config' method
  below).
* If "Fancy URLs" are not enabled, urls from above need to include "index.php" at
  the root. ( e.g. http://example.org/statusnet/api becomes http://www.example.org/statusnet/index.php/api )
* The `since_id` parameter does not work as documented by Twitter. Twitter says of
  `since_id`: "There are limits to the number of Tweets which can be accessed
  through the API. If the limit of Tweets has occured since the `since_id`, the
  `since_id` will be forced to the oldest ID available." However, GNU social will
  return the newest notices (or the newest back from max_id, if present)! Also, a
  `since_id` <= 0 will be ignored.

## Timeline resources

### statuses/public_timeline

Returns the 20 most recent notices, including repeats if they exist, from
non-protected users.

### statuses/home_timeline

Returns the 20 most recent notices, including repeats if they exist, posted by the
authenticating user and the users they follow. This is the same timeline seen by a
user when they login to their instance. This method is identical to
statuses/friends_timeline, except that this method always includes repeats.

### statuses/friends_timeline

Alias of statuses/home_timeline

### statuses/friends_timeline/:username

Alias of statuses/home_timeline for the specified username

### statuses/mentions

Returns the 20 most recent mentions (notices containing @username) for the
authenticating user.

This method will not include repeats in the XML and JSON responses unless the
include_rts parameter is set. The RSS and Atom responses will always include repeats
as notices prefixed with RT.

### statuses/replies

Alias of statuses/mentions

### statuses/replies/:username

Alias of statuses/mentions for the specified username

### statuses/user_timeline

Returns the 20 most recent notices posted by the authenticating user. It is also
possible to request another user's timeline by using the screen\_name or user_id
parameter. The other users timeline will only be visible if they are not protected,
or if the authenticating user's follow request was accepted by the protected user.

This method will not include repeats in the XML and JSON responses unless the
include_rts parameter is set. The RSS and Atom responses will always include
repeats as notices prefixed with RT, regardless of provided parameters.

### statuses/retweeted\_to_me

Not implemented.

### statuses/retweeted\_by_me

Not implemented.

### statuses/retweets\_of_me

Not implemented.

## Status resources

### statuses/show/:id

Returns a single notice, specified by the id parameter. The notice's author will be
returned inline.

### statuses/update

Post a new notice as the authenticating user.

Additional 'media' parameter allows binary multimedia uploads (images, etc.). Format
post data as multipart/form-data when using the 'media' parameter.

### statuses/destroy/:id

Destroys the notice specified by the required ID parameter. The authenticating user
must be the author of the specified notice. Returns the destroyed notice if successful.

### statuses/retweet/:id

Repeats a notice. Returns the original notice with repeat details embedded.

## User resources

### statuses/friends

Returns the user's subscriptions (friends) as an array of profiles.

### statuses/followers

Returns the user's subscribers (followers) as an array of profiles.

### users/show

Returns extended information of a given user, specified by ID or screen name as per
the required id parameter.

## Direct message resources

### direct_messages

Returns the 20 most recent direct messages sent to the authenticating user. The XML
and JSON versions include detailed information about the sender and recipient user.

### direct_messages/sent

Returns the 20 most recent direct messages sent by the authenticating user. The XML
and JSON versions include detailed information about the sender and recipient user.

### direct_messages/new

Sends a new direct message to the specified user from the authenticating user.
Requires both the user and text parameters and must be a POST. Returns the sent
message in the requested format if successful.

### direct_messages/destroy

Not implemented.

## Friendships resources

### friendships/create

Allows the authenticating users to follow the user specified in the ID parameter.
Returns the befriended user in the requested format when successful. Returns a
string describing the failure condition when unsuccessful.

If you are already friends with the user a HTTP 403 may be returned, though for
performance reasons you may get a 200 OK message even if the friendship already
exists.

Note that users cannot subscribe to remote profiles using this API.

### friendships/destroy

Allows the authenticating users to unfollow the user specified in the ID parameter.
Returns the unfollowed user in the requested format when successful. Returns a
string describing the failure condition when unsuccessful.

Users can unsubscribe to a remote profile using this API, but it's preferred to use
numeric IDs to nicknames.

### friendships/exists

Test for the existence of friendship between two users. Will return true if user\_a
follows user_b, otherwise will return false. Authentication is required if either
user A or user B are protected. Additionally the authenticating user must be a
follower of the protected user.

### friendships/show

Returns detailed information about the relationship between two users.

## Friends and subscribers resources

### friends/ids

Returns an array of numeric IDs for every user the specified user is subscribed to.
This method is powerful when used in conjunction with users/lookup.

### followers/ids

Returns an array of numeric IDs for every user subscsribed to the specified user.
This method is powerful when used in conjunction with users/lookup.

## Account resources

### account/verify_credentials

Returns an HTTP 200 OK response code and a representation of the requesting user if
authentication was successful; returns a 401 status code and an error message if
not. Use this method to test if supplied user credentials are valid.

### account/end_session

Not implemented.

### account/update\_delivery_device

Not implemented.

### account/rate\_limit_status

Returns the remaining number of API requests available to the requesting user before
the API limit is reached.

We have no rate limit, so this always returns 150 hits left.

### account/update\_profile\_background_image

Updates the authenticating user's profile background image. This method can also be
used to enable or disable the profile background image.

### account/update\_profile_image

Updates the authenticating user's profile image. Note that this method expects raw
multipart data, not a URL to an image.

## Favorite resources

### favorites

Returns the 20 most recent favorite statuses for the authenticating or specified
user in the requested format.

### favorites/create/:id

Favorites the status specified in the ID parameter as the authenticating user.
Returns the favorite status when successful.

### favorites/destroy/:id

Un-favorites the status specified in the ID parameter as the authenticating user.
Returns the un-favorited status in the requested format when successful.

## Notification resources

### notifications/follow

Not implemented.

### notifications/leave

Not implemented.

## Block resources

### blocks/create

Blocks the specified user from following the authenticating user. In addition the
blocked user will not show in the authenticating users mentions or timeline (unless
retweeted by another user). If a follow or friend relationship exists it is
destroyed.

### blocks/destroy

Un-blocks the user specified in the ID parameter for the authenticating user.
Returns the un-blocked user in the requested format when successful. If
relationships existed before the block was instated, they will not be restored.

### blocks/exists

Not implemented.

### blocks/blocking

Not implemented.

## Help resources

### help/test

Returns the string "ok" in the requested format with a 200 OK HTTP status code. This
method is great for sending a HEAD request to determine our servers current time.

## OAuth resources

It is strongly recommended you use HTTPS for all OAuth authorization steps.

### oauth/request_token

Allows a Consumer application to obtain an OAuth Request Token to request user
authorization. This method fulfills Section 6.1 of the OAuth 1.0 authentication
flow. It is strongly recommended you use HTTPS for all OAuth authorization steps.

### oauth/authorize

Allows a Consumer application to use an OAuth Request Token to request user
authorization. This method fulfills Section 6.2 of the OAuth 1.0 authentication
flow. Desktop applications must use this method (and cannot use GET oauth/authenticate).

### oauth/access_token

Allows a Consumer application to exchange the OAuth Request Token for an OAuth
Access Token. This method fulfills Section 6.3 of the OAuth 1.0 authentication flow.
The OAuth access token may also be used for xAuth operations.

## Search

The search method supports the following optional URL parameters:

* **callback**: if supplied when using the JSON format, the response will use the
  JSONP format with a callback of the given name.
* **rpp**: the number of notices to return per page, up to a max of 100.
* **page**: the page number (starting at 1) to return.
* **since_id:**: returns notices with ids greater than the given id.

Note:

* The search does not support operators, such as "from:", "to:" and booleans.
* Notice content is HTML-encoded.

### search

Returns relevant notices that match a specified query.

### Atom

To request search results in Atom, append your URL-encoded query as a parameter to
the search method and specify the Atom format:

`%%site.server%%/%%site.path%%api/search.atom?q=<query>`

### JSON

To request search results in JSON, append your URL-encoded query as a parameter to
the search method and specify the JSON format:

`%%site.server%%/%%site.path%%api/search.json?q=<query>`

## Additional resources

These are extensions to the Twitter API that expose additional functionality.

### Group resources

#### statusnet/groups/timeline

Shows a group's timeline. Similar to other timeline resources.

#### statusnet/groups/show

Show a groups profile.

#### statusnet/groups/create

Create a new group.

#### statusnet/groups/join

Join a group.

#### statusnet/groups/leave

Leave a group.

#### statusnet/groups/list

Show the groups a given user is a member of.

#### statusnet/groups/list_all

List all local groups.

#### statusnet/groups/membership

List the members of a given group.

#### statusnet/groups/is_member

Determine whether a given user is a member of a given group.

### Tag resources

#### statusnet/tags/timeline

Shows a tag's timeline. Similar to other timeline resources.

### Media resources

#### statusnet/media/upload

Endpoint for uploading an image. Returns a URL that can be used in a status update.
Format post data as multipart/form-data.

### Configuration

#### statusnet/config

Show an instance's configuration information.

Of special note is the `<private>` element (config/site/private), which indicates
whether a site is private. When a site is configured as private every other API
method requires authentication, including the public timeline (`/api/statuses/public_timeline.format`).

path: doc-src/twitterapi


code:
<?php
/**
 * Note : Code is released under the GNU LGPL
 *
 * Please do not change the header of this file
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This library 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 Lesser General Public License for more details.
 */

/**
 * The AcceptHeader page will parse and sort the different
 * allowed types for the content negociations
 *
 * @author Pierrick Charron <pierrick@webstart.fr>
 */
class AcceptHeader extends \ArrayObject
{
    /**
     * Constructor
     *
     * @param string $header Value of the Accept header
     * @return void
     */
    public function __construct($header)
    {
        $acceptedTypes = $this->_parse($header);
        usort($acceptedTypes, [$this, '_compare']);
        parent::__construct($acceptedTypes);
    }

    /**
     * Parse the accept header and return an array containing
     * all the informations about the Accepted types
     *
     * @param string $data Value of the Accept header
     * @return array
     */
    private function _parse($data)
    {
        $array = [];
        $items = explode(',', $data);
        foreach ($items as $item) {
            $elems = explode(';', $item);

            $mime  = current($elems);
            $types = explode('/', $mime);

            if (!isset($types[1])) {
                continue;
            }

            $acceptElement = [
                'raw'     => $mime,
                'type'    => trim($types[0]),
                'subtype' => trim($types[1]),
            ];

            $acceptElement['params'] = [];
            while (next($elems)) {
                list($name, $value) = explode('=', current($elems));
                $acceptElement['params'][trim($name)] = trim($value);
            }

            $array[] = $acceptElement;
        }
        return $array;
    }

    /**
     * Compare two Accepted types with their parameters to know
     * if one media type should be used instead of an other
     *
     * @param array $a The first media type and its parameters
     * @param array $b The second media type and its parameters
     * @return int
     */
    private function _compare($a, $b)
    {
        $a_q = isset($a['params']['q']) ? floatval($a['params']['q']) : 1.0;
        $b_q = isset($b['params']['q']) ? floatval($b['params']['q']) : 1.0;
        if ($a_q === $b_q) {
            $a_count = count($a['params']);
            $b_count = count($b['params']);
            if ($a_count === $b_count) {
                if ($r = $this->_compareSubType($a['subtype'], $b['subtype'])) {
                    return $r;
                } else {
                    return $this->_compareSubType($a['type'], $b['type']);
                }
            } else {
                return $a_count < $b_count;
            }
        } else {
            return $a_q < $b_q;
        }
    }

    /**
     * Compare two subtypes
     *
     * @param string $a First subtype to compare
     * @param string $b Second subtype to compare
     * @return int
     */
    private function _compareSubType($a, $b)
    {
        if ($a === '*' && $b !== '*') {
            return 1;
        } elseif ($b === '*' && $a !== '*') {
            return -1;
        } else {
            return 0;
        }
    }
}