function Player(options) {
    //additional player events
    this.defaultOptions = {
        id:            null,
        title:         null,
        src:           null,
        objectId:      null,
        //events
        onInitialized:    function(){},
        onDisposed:       function(){},
        onLaunched:       function(){},
        onRetrieved:      function(obj){},
        onPlay:           function(){},
        onEnded:          function(){},
        onDownloading:    function(obj){},
        onProgress:       function(obj){},
        onStateChanged:   function(state){},
        onPause:          function(){},
        onStop:           function(){},
        onBitrateChanged: function(){}
    };

    this.options = extendObject(this.defaultOptions, options);

    this.id                  = this.options.id;
    this.objectId            = this.options.objectId;
    this.fileSrc             = this.options.src;
    this.itemId              = this.options.itemId
    this.itemTitle           = this.options.title;
    this.itemDescription     = this.options.description;
    this.onPlayerInitialized = this.options.onInitialized;
    this.onPlayerDisposed    = this.options.onDisposed;
    this.position            = 0;


    this.getId = function() {
        return this.id;
    }

    this.getPosition = function()
    {
        return this.position;
    }

    this.setItemTitle = function (itemTitle) {
        this.itemTitle = itemTitle;
    }

    this.setFileSrc = function (fileSrc) {
        this.fileSrc = fileSrc;
    }


    this.SceneIntializedTracking = function() {
        this.initEventFlashListener();
        this.onPlayerInitialized();
    }

    this.SceneDisposeTracking = function() {
        this.onPlayerDisposed();
        this.disposeEventFlashListener();
    }

    this.initEventFlashListener = function() {
        var playerEvents = new PlayerEvents();
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_LAUNCHED,        'players.getPlayer(' + this.getId() + ').MediaLaunched()');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_RETRIEVED,       'players.getPlayer(' + this.getId() + ').MediaRetrieved');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_PLAY,            'players.getPlayer(' + this.getId() + ').MediaPlay');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_ENDED,           'players.getPlayer(' + this.getId() + ').MediaEnded');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_DOWNLOADING,     'players.getPlayer(' + this.getId() + ').MediaDownloading');
        //this.getDomObject().AddExternalListener(playerEvents.MEDIA_PROGRESS,        'players.getPlayer(' + this.getId() + ').MediaProgress');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_PROGRESS,        'players.getPlayer(' + this.getId() + ').MediaProgressTranscript');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_STATE_CHANGED,   'players.getPlayer(' + this.getId() + ').MediaStateChanged');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_PAUSE,           'players.getPlayer(' + this.getId() + ').MediaPause');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_STOP,            'players.getPlayer(' + this.getId() + ').MediaStop');
        this.getDomObject().AddExternalListener(playerEvents.MEDIA_BITRATE_CHANGED, 'players.getPlayer(' + this.getId() + ').MediaBitrateChanged');
    }

    this.disposeEventFlashListener = function() {
        var playerEvents = new PlayerEvents();
        /*
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_LAUNCHED);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_RETRIEVED);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_PLAY);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_ENDED);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_DOWNLOADING);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_PROGRESS);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_PROGRESS);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_STATE_CHANGED);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_PAUSE);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_STOP);
        this.getDomObject().RemoveExternalListener(playerEvents.MEDIA_BITRATE_CHANGED);
        */
    }

    /**
     * function to load an Item Id
     */
    this.loadMediaById = function (itemId) {
        if (itemId != undefined)
            this.getDomObject().loadMediaById(itemId);
    }

    /**
     * function to load a XML data
     */
    this.loadMediaByXml = function (xmlUrl) {
        this.getDomObject().loadMediaByXml(xmlUrl);
    }

    /**
     * function to load an Url
     */
    this.loadMediaByUrl = function (urlVideo) {
        this.getDomObject().loadMediaByUrl(urlVideo);
    }

    /**
     * function to playMedia
     */
    this.playMedia = function () {
        this.getDomObject().playMedia();
    }

    /**
     * function to pauseMedia
     */
    this.pauseMedia = function () {
        this.getDomObject().pauseMedia();
    }

    /**
     * function to stopMedia
     */
    this.stopMedia = function () {
        this.getDomObject().stopMedia();
    }

    /**
     * function to switchPlayPauseMedia
     */
    this.switchPlayPauseMedia = function () {
        this.getDomObject().switchPlayPauseMedia();
    }

    /**
     * function to seekMedia
     */
    this.seekMedia = function (value) {
        if (value != undefined)
            this.getDomObject().seekMedia(value);
    }

    /**
     * PMS - function to search Rich Transcript word
     */
    this.searchRichTranscript = function (value) {
        if (value != undefined) 
            this.getDomObject().searchRichTranscript(value);
    }

    /***
     *  Catch this event. Theses functions are the callback of the smartplayer. Active if activePlayerControl is called
     */
    this.MediaLaunched = function () {
        this.options.onLaunched();
    }

    this.MediaRetrieved = function (obj) {
        this.options.onRetrieved(obj);
        this.fileSrc         = obj.source;
        this.itemId          = obj.id;
        this.itemTitle       = obj.title;
        this.itemDescription = obj.description;
        // FIXME get complete media object
        // this._item = obj._object;
    }

    this.MediaPlay = function () {
        this.options.onPlay();

        this.logForSimpleStats('item', this.fileSrc, this.itemTitle, 4);
        this.logForSimpleStats('state', 'PLAYING', null, 4);
    }

    this.MediaEnded = function () {
        this.options.onEnded();

        this.logForSimpleStats('state', 'COMPLETED', null, 4);
    }

    this.MediaDownloading = function(obj) {
        this.options.onDownloading(obj);

        this.logForSimpleStats('load', obj.bytesLoaded, obj.bytesTotal, 4);
    }

    this.MediaProgress = function (obj) {
        this.options.onProgress(obj);

        this.position = obj.position;
        if (obj.duration != 'Infinity')
            this.logForSimpleStats('time', obj.position, obj.duration - obj.position, 4);

        // FIXME Should be called from Media Progress event (see above comment line)
        this.MediaProgressTranscript(obj);
    }

    // PMS
    this.MediaProgressTranscript = function (obj) {
        var segments = document.getElementsByClassName('richTranscriptSegment');
        for (var i = 0; i < segments.length; ++i) {
            var beginTime = parseInt(segments[i].getAttribute('data-begintime').replace(',', '.'));
            var positionFloor = Math.floor(obj.position);
            if (positionFloor == beginTime) {
                // Removing highlight for other segments
                for (var j = 0; j < segments.length; ++j) {
                    segments[j].className = segments[j].className.replace(" playing", "");
                }
                
                // Highlighting the playing segment
                segments[i].className += " playing";
            }
            else {
                // Removing highlight for other segments
                segments[i].className = segments[i].className.replace(" playing", "");
            }
        }
    }
    
    this.MediaStateChanged = function (state) {
        this.options.onStateChanged(state);

        // "state" equals to "true" means
        // the player is buffering
        if (state == false) {
            this.logForSimpleStats('state', 'PLAYING', null, 4);
        }
        else {
            this.logForSimpleStats('state', 'BUFFERING', null, 4);
        }
    }

    this.MediaPause = function () {
        this.options.onPause();

        this.logForSimpleStats('state', 'PAUSE', null, 4);
    }

    this.MediaStop = function () {
        this.options.onStop();

        this.logForSimpleStats('state', 'ILDE', null, 4);
    }

    this.MediaBitrateChanged = function (bitrate) {
        this.options.onBitrateChanged(bitrate);
    }

    this.logForSimpleStats = function (typ, pr1, pr2, version) {
        getUpdate(typ, pr1, pr2, this.getId(), version);
    }

    this.ShowBlog = function () {
      this.getDomObject().ShowBlog();
    }
     
    this.ShowSendTo = function () {
      this.getDomObject().ShowSendTo();
    }
     
    this.ShowChapter = function () {
      this.getDomObject().ShowChapter();
    }
     
    this.ShowMediaInformation = function () {
      this.getDomObject().ShowMediaInformation();
    }
     
    this.ShowBrainsonic = function () {
      this.getDomObject().ShowBrainsonic();
    }

    this.getDomObject = function () {
        return document.getElementById(this.options.objectId);
    }
}

// toolkit methods comming from jQuery libs

var extendObject = function() {
    // copy reference to target object
    var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {
        deep = target;
        target = arguments[1] || {};
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && typeof target !== "function" )
        target = {};

    // extend jQuery itself if only one argument is passed
    if ( length == i ) {
        target = this;
        --i;
    }

    for ( ; i < length; i++ )
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null )
            // Extend the base object
            for ( var name in options ) {
                var src = target[ name ], copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy )
                    continue;

                // Recurse if we're merging object values
                if ( deep && copy && typeof copy === "object" && !copy.nodeType )
                    target[ name ] = extendObject( deep,
                        // Never move original objects, clone them
                        src || ( copy.length != null ? [ ] : { } )
                    , copy );

                // Don't bring in undefined values
                else if ( copy !== undefined )
                    target[ name ] = copy;
            }

    // Return the modified object
    return target;
};

