Source: conversant-api.js

"use strict"
let Rx = require('rx-lite')
let m = require('./model')
let mapper = require('./mapper')

/**
 * @class API
 * base class for api implementation.
 */
class API {
	constructor(observer, observable) {
		this.mapper = new mapper.Mapper()
		//this.futures = new Map
		this.channelSubject = Rx.Subject.create(observer, observable)
		this.channelSubject.subscribe((x) => {console.log(x);}, (e) => {console.log(e);})
	}

	_send(data){
		this.channelSubject.onNext(data)
	}

	/**
	 * addResponder
	 * The method allows you to register handlers for data of a certain 'type'.  When data of this
	 * type passes through the stream each of your registered handlers will be called with an
	 * opportunity to react on this data.
	 *
	 * @param type {String} A String indicating the ES6 class name that you want to subscribe to
	 * @param fun {function} The function that will receive data. The data will be instances of the
	 * type parameter passed in.
	 *
	 * @returns {Rx.Subscription}
     */
	addResponder(type, fun){
		let subject = new Rx.Subject()
		this.channelSubject.filter( (x) => x.$type === type ).subscribe(subject)
		return subject.subscribe( (x) => fun(x))
	}

	_addFuture(type, fun){
		let subject = new Rx.Subject()
		this.channelSubject.filter( (x) => x.$type === type ).subscribe(subject)
		let subscription = subject.subscribe( (x) => {
			fun(x)
			subscription.dispose()
		})
	}

	/**
	 * addGuest(profile:Auth.ProfileInfo):Future[Auth.PrimaryProfile]
	 * Add a guest account to the system.  You will need to pass in the provider type and unique
	 * id for that provider.  Examples of providers and valid id are:
	 *    provider: 'email',  id: 'user@gmail.com'
	 *    or
	 *    provider: 'phone', id: '+1.777.222.1111'
	 *
	 * @param profile {Auth.ProfileInfo}
	 * profile for the new guest of type 'm.Auth.ProfileInfo'
	 * @returns promise {Promise} that will be filled with {Auth.PrimaryProfile}
	 * This function returns a promise that will be filled with an instance of
	 * 'm.Auth.PrimaryProfile' for the guest that was created
     */
	addGuest(profile) {
		let p = new Promise((resolve, reject) => {
			m.Type.check(profile, m.Auth.ProfileInfo, reject)
			this._addFuture(m.Auth.PrimaryProfile.type(), resolve)
			this.send(this.mapper.write(profile))
		})
		return p
	}

	/**
	 * def syncUser(sync:Collaboration.SyncUserEvent):Unit
	 * Synchronize user state.
	 *
	 * @param sync {Collaboration.SyncUserEvent}
	 * The synchronize event to be shared with other users on the system.  This parameter is
	 * of type 'm.Collaboration.SyncUserEvent'
     */
	syncUser(sync){
		m.Type.check(profile, m.Collaboration.SyncUserEvent)
		this.send(this.mapper.write(sync))
	}

	/**
	 * def syncView(sync:Collaboration.SyncViewEvent):Unit
	 * Synchronize view/app state in the synchronization pannel.
	 *
	 * @param sync {m.Collaboration.SyncViewEvent}
	 * The synchronize event bring application state in sync.  This parameter is
	 * of type 'm.Collaboration.SyncViewEvent'
     */
	syncView(sync){
		m.Type.check(profile, m.Collaboration.SyncViewEvent)
		this.send(this.mapper.write(sync))
	}

	// ** INIT types...

	// def sendChatMessage(author:Auth.ProfileInfo, cId: String, v:Collaboration.ViewerState, content:Option[String], contentClass:Collaboration.ContentClass):Unit
	// def getUser(uuid:String):Future[Auth.PrimaryProfile]
	// def getProfileRelationship(rel:Graph.GetProfileRelationships):Future[Graph.ProfileRelationship]
	// def addContentToUserFavorites(userId:String, profile: Auth.ProfileInfo, content:Collaboration.Content):Future[Collaboration.TaggedContent]
	// def loadApplication(load:Apps.App):Future[Apps.Launch]
	// def getOrganization(appName:String, orgId:String):Future[Auth.Organization]
	// def updateProfile(update:Auth.UpdateProfile):Future[Auth.ProfileInfo]
	// def addCollaborationMembers(c:Collaboration.Collaboration, members:Set[Auth.ProfileInfo]):Future[Collaboration.Collaboration]
	// def getCollaborationContent(cid:String, before:Option[String] = None):Future[Collaboration.Collaboration]
	// def getFiles(orgId:String):Future[Resource.FileList]
	// def saveFile(file:Resource.File):Future[Resource.File]
	// def maxSeach(m:Max.Search):Future[Max.SearchResultList]
	// def getCollaborationContentTagged(userId:String, tag:String, cid:Option[String] =  None):Future[Collaboration.TaggedContentList]
	// def createInvite(collaborationId:String, from:Auth.ProfileInfo, to:Auth.ProfileInfo):Future[Collaboration.InviteLink]
}

/**
 * AppParameters is the initilization parameter passed in to your application.
 * @see {ConversantAPI}
 */
class AppParameters{

	/**
	 *
	 * @param collaboration {Collaboration.Collaboration}
	 * @param profile {Auth.ProfileInfo}
	 * @param team {Collaboration.SyncUserEvent[]}
     * @param peers {Peers.PeerState[]}
     */
	constructor(collaboration, profile, team, peers){
		this.collaboration = Type.check(collaboration, m.Collaboration.Collaboration)
		this.profile = Type.check(profile, m.Auth.ProfileInfo)
		this.team = team.map( (t) => Type.check(t, m.Collaboration.SyncUserEvent) )
		this.peers = peers.map( (p) => Type.check(p, m.Peers.PeerState) )
	}
}

/**
 * @class ConversantAPI
 * An implementation of the API that uses window.postMessage as the channel to Observe and addEventListener(message)
 * as the Observable
 */
class ConversantAPI extends API{

	/**
	 * Construct {Rx.Observer} and {Rx.Observable} for communication with the parent frame.
	 */
	constructor(){
		let observer = Rx.Observer.create((data) => {
			window.top.postMessage(data, '*')
		})
		console.log('Observable create')
		let observable = Rx.Observable.create( (obs) => {
			console.log('Observable')
			window.addEventListener('message', (event) => {
				console.log('origin',event)
				obs.onNext(JSON.parse(event.data))
			}, false)
			//worker.onerror = function (err) {
			//	obs.onError(err);
			//};

			return () => {
				// onComplete
			}
		})
		super(observer, observable)
	}

	/**
	 *
	 * @param fun {function}
	 * The function to be called when the application can be initialized.  The function will be called with
	 * an instance of {AppParameters}.
     */
	init(fun){
		let pCollaboration = super._addFuture(m.Apps.InitCollaboration.type())
		let pPofile = super._addFuture(m.Apps.InitProfile.type())
		let pTeam = super._addFuture(m.Apps.InitTeam.type())
		let pPeers = super._addFuture(m.Apps.InitPeers.type())

		Promise.all([pCollaboration, pPofile, pTeam, pPeers]).then( (vals) => {
			let appParams = new AppParameters( vals[0], vals[1], vals[2], vals[3]  )
			fun(appParams)
		})
		super._send(super.mapper.write(m.Apps.Init))
	}

}


module.exports = {
	ConversantAPI: ConversantAPI,
	AppParameters: AppParameters
};
window.ConversantAPI = module.exports;