/*!
 * Copyright 2017 Vpn.Email network security technology Canada Inc. All Rights Reserved.
 *
 * Vpn.Email network technolog Canada Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as Compress from './compress'
import * as Async from 'async'
import * as shortID from 'shortid'
import * as Crypto from 'crypto'
import * as execImap from './execImap'
const maxAclias = 2

export default class imapConnect {

	public mainImap: execImap.execImap[] = []
	private pairConnectPool: IpairConnect[] = []
	private isAliasUp = false
	private totalRead = 0
	private totalReadCount = 0

	private _newMail ( buffer: Buffer ) {
		
		this.totalRead += buffer.length
		this.totalReadCount ++
		const y = Compress.openPacket ( buffer )
		//console.log (`======> [${this.users.imapUserName}][${this.users.serverMailBoxName}] total read count :[${this.totalReadCount}], total byte [${this.totalRead}]`)
		//console.log ('new Mail = ', y.command)
		switch ( y.command ) {
			case 0:
			case 1:
			case 2:
			case 5:
				return this.newMail ( y )
			case 3:
				const CallBack = this.CallBackPool.get ( y.uuid )
				if ( ! CallBack )
					console.log ( y.uuid, 'got NewMail peer connect but cant find uuid' )
				this.CallBackPool.delete ( y.uuid )
				return CallBack ()
			default:
				return console.log ('imapCluster->_newMail unknow y.command = ', y.command )
		}
		
	}

	private preNewMail ( buffer: Buffer ) {
		const data = Compress.decrypt ( buffer, this.password, ( err, data ) => {
			if ( err ) {
				return console.log ( '=======> preNewMail Compress.decrypt ERROR', err.message )
			}
			if ( !data || !data.length )
				return console.log ( '=======> preNewMail no data ERROR' )
			try {
				const dataArray = JSON.parse ( data )
				
				Async.each ( dataArray, n => {
                    this._newMail ( new Buffer ( n['data'], 'utf8' ))
				})
			} catch ( e ) {
				return console.log ( '=======> preNewMail JSON parse ERROR' )
			}
		})
	}

	private pushToPool ( isAlias: boolean, _execImap: execImap.execImap ) {
		const u: execImap.VE_IimapPool = {
			isAlias: isAlias,
			execImap: _execImap,
			name: shortID.generate()
		}

		
		if ( isAlias )
			return this.subImapPool.push ( u )
		return this.mainImapPool.push ( u )
	}

	private getPairFolder () {

		for ( let i = 0; i < maxAclias; i ++ ) {
			const _listenFolder = ( this.isServer ? this.users.serverMailBoxName : this.users.uuid ) + i
			const _saveFolder = ( this.isServer ? this.users.uuid : this.users.serverMailBoxName ) + i
			
			const ret: IpairConnect = {
				saveFolder: Crypto.createHash ( 'md5' ).update ( _saveFolder ).digest( 'hex' ),
				listenFolder: Crypto.createHash ( 'md5' ).update ( _listenFolder ).digest( 'hex' )
			}
			this.pairConnectPool.push ( ret )
		}
	}

	constructor ( private users: IinputData, private newMail: ( data: Compress.packetBuffer ) => void, private subImapPool: execImap.VE_IimapPool [], private mainReconnectReady: () => void,
		private subReconnectReady: () => void, 
		private mainImapPool: execImap.VE_IimapPool [], private password: string, private isServer: boolean, private CallBackPool: Map <string, () => void>, private doFock: boolean, private endCall ) {
		this.getPairFolder ()
		this.connect ( users, password )
	}

	public connect ( users: IinputData, password: string ) {
		const listenFolder = this.isServer ? users.serverMailBoxName: users.uuid
		const saveFolder = !this.isServer ? users.serverMailBoxName: users.uuid
		const dummyImap = new execImap.execImap ( users, null, saveFolder, null, this.mainReconnectReady,  this.doFock, this.endCall )

		this.pushToPool ( false, dummyImap )
		
		/*
		const dummyImap1 = new execImap.execImap ( users, null, saveFolder, null, this.doFock, this.endCall )
		this.pushToPool ( false, dummyImap1 )
		/*
		const dummyImap2 = new execImap.execImap ( users, null, saveFolder, null, this.doFock, this.endCall )
		this.pushToPool ( true, dummyImap2 )
		/*
		
		if ( this.isServer ) {
			const dummyImap3 = new execImap.execImap ( users, null, saveFolder, null, this.doFock, this.endCall )
			this.pushToPool ( true, dummyImap3 )

			const dummyImap4 = new execImap.execImap ( users, null, saveFolder, null, this.doFock, this.endCall )
			this.pushToPool ( true, dummyImap4 )

			const dummyImap5 = new execImap.execImap ( users, null, saveFolder, null, this.doFock, this.endCall )
			this.pushToPool ( true, dummyImap5 )
			
		}
		
		*/
		
		this.mainImap.push ( new execImap.execImap ( users, listenFolder, null, buffer => { this.preNewMail ( buffer )}, null, this.doFock, this.endCall ))
		
		this.ConnectPair ()
		
	}

	public ConnectPair () {
		if ( this.isAliasUp )
			return
		this.isAliasUp = true
		console.log ( 'start pair length = ', this.pairConnectPool.length )

		Async.each ( this.pairConnectPool, ( n, down ) => {

			this.mainImap.push ( new execImap.execImap ( this.users, n.listenFolder, null, buffer => { this.preNewMail ( buffer )} , null, this.doFock, this.endCall))
			const sss = new execImap.execImap ( this.users, null, n.saveFolder, null, this.mainReconnectReady, this.doFock, this.endCall )
			
			this.pushToPool ( true, sss )

		}) 

		
	}
	
}



