package com.dbs.mplus.fatima.framework.processor;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.webkit.WebView;

import com.dbs.mplus.fatima.consent.sign.SignWrapper;
import com.dbs.mplus.fatima.framework.MPlusFrameworkConstants;
import com.dbs.mplus.fatima.framework.processor.msg.Message;
import com.dbs.mplus.fatima.framework.processor.msg.MessageParser;
import com.dbs.mplus.fatima.framework.util.MPlusIntentUtil;
import com.dbs.mplus.fatima.framework.util.MPlusLogUtil;
import com.dbs.mplus.fatima.framework.util.MPlusPreferenceUtil;
import com.dbs.mplus.fatima.framework.util.MPlusStringUtil;

import org.json.JSONException;

import java.util.Map;

/**
 * 서버에서 수신된 메시지를 처리한다.
 *
 * @author hyeeun 
 */
public abstract class MPlusMessageProcessor implements Runnable {
    protected final Activity activity;
    protected final WebView webView; 
    protected final String jsonStr;

    /**
     * 생성자
     * @param activity 메시지를 받은 뷰 
     * @param webView 자바스크립트 처리용 
     * @param jsonStr 처리할 메시지
     */
    public MPlusMessageProcessor(Activity activity, WebView webView, String jsonStr) {
        this.activity = activity;
        this.webView = webView; 
        this.jsonStr = jsonStr;
    }

    @Override
    public void run() {
        Message message = null;

        // 수신된 메시지를 분석하고
        try {
            message = MessageParser.convert(this.jsonStr);
        }
        catch(final JSONException ex) {
            MPlusLogUtil.ERROR(this.getClass(), this.jsonStr, ex);
            return;
        }

        // 처리한다.
        switch(message.getType()) {
            case ERROR:
                this.processError(message);
                break;

            case COMMAND :
                this.processCommand(message);
                break;

            default : // 유효성 검사는 했지만 혹시 모르니까 추가해둠
                MPlusLogUtil.ERROR(this.getClass(), "invalid message type : " + message.getType());
                break;
        }
    }

    /**
     * 에러 메시지 실행
     * @param msg
     */
    private void processError(Message msg) {
        // 경대병원 소스도... 에러 수신시 로그 찍는거 말고는 하는게 없어서 일단 동일하게 처리함
        MPlusLogUtil.ERROR(this.getClass(), msg.getValueMap().toString());
    }

    /**
     * 명령 메시지 실행
     * @param msg
     */
    private void processCommand(Message msg) {
    	MPlusLogUtil.DEBUG(this.getClass(), msg.toString());
    	
        switch(msg.getFunction()) {
            case BROWSING : // 웹 페이지 이동
            	this.processBrowsing(msg);
            	break;
            
            case SYSTEM_BROWSING : // 시스템에 설치된 웹 브라우저로 로딩
            {
                final String key = MPlusFrameworkConstants.MSG_VALUE_KEY.BROWSING_URL.toString();
                final String url = msg.getValueMap().get(key); 
                
                final Intent intent = MPlusIntentUtil.getSystemBrowsingIntent(url);
                this.activity.startActivity(intent);
            }
            break; 
            
            case POPUP : // 팝업으로 페이지 이동
            	this.processAuthPopupBrowsing(msg);
            	break; 

            case TOKEN : // 토큰요청
            {
                // 저장된 토큰 꺼내기 
                final MPlusPreferenceUtil p = MPlusPreferenceUtil.getInstance(this.activity);
                String deviceToken = p.getDeviceToken();

                if(MPlusStringUtil.isEmpty(deviceToken)) {
                    deviceToken = MPlusFrameworkConstants.NOT_ALLOWED_DEVICE_TOKEN_BY_USER;
                }

                // 알려주기 
                final Map<String, String> map = msg.getValueMap(); 
                // 자바 스크립트 실행 문자열 만들기    
                final String script = MPlusStringUtil.getCallbackFnString(
                		map.get(MPlusFrameworkConstants.MSG_VALUE_KEY.CALLBACK_FN.toString()),
                		p.getDeviceToken(), 
                		MPlusFrameworkConstants.CERT_TYPE);
                
                MPlusLogUtil.DEBUG(this.getClass(), script);
                
                // 실행하기. intent로 호출하면 화면이 전이됨 
                this.webView.loadUrl(script);
            }
            break;

            case SCREEN : // 화면처리 (화면회전)
            {
            	final Map<String, String> map = msg.getValueMap();
            	final String orientation = map.get(MPlusFrameworkConstants.MSG_VALUE_KEY.ORIENTATION.toString());

            	// 세로
            	if(MPlusFrameworkConstants.MSG_SCREEN_ORIENTATION_PORTRAIT.equals(orientation)) {
            		this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            	}
            	// 가로
            	else {
            		this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            	}
            }
            break;
            case POPUP_BROWSING: // 팝업 브라우징
                this.processExtraPopupBrowsing(msg);
                break;
            case VERSION : // 버전확인
                this.processVersion(msg);
                break;
            case CONSENT: // 동의서 오픈 요청
                this.processConsentReq(msg);
                break;
            case CONSENT_SIGN: // 동의서 일괄 서명 요청
                this.processConsentSignReq(msg);
                break;
            case LOGOUT:
                // 로그아웃 인증서 모두 정리
                SignWrapper.getInstance().deleteAll();
                break;
            case EXIT : // 앱 종료
            {
                // push token 삭제. token update를 대비해서(영원히 토큰이 유지되지는 않으니까) 한번씩 삭제
                final MPlusPreferenceUtil p = MPlusPreferenceUtil.getInstance(this.activity.getApplicationContext());
                p.setDeviceToken(null);
                // 종료처리
                this.processAppExit(msg);
            }
            break;


            default :
                MPlusLogUtil.ERROR(this.getClass(), "invalid function type : " + msg.getFunction());
                break;
        }
    }

    /**
     * 기본 브라우징 
     * @param msg
     */
    protected abstract void processBrowsing(Message msg);
    
    /**
     * 인증용 팝업 브라우징
     * @param msg
     */
    protected abstract void processAuthPopupBrowsing(Message msg);
    
    /**
     * 앱 종료  
     * @param msg
     */
    protected abstract void processAppExit(Message msg);
    /**
     * 프로그램 정보 확인
     * @param msg
     */
    protected abstract void processVersion(Message msg);

    /**
     * 팝업 브라우징
     * @param msg
     */
    protected abstract void processExtraPopupBrowsing(Message msg);

    /**
     * 전자동의서 호출
     */
    protected abstract void processConsentReq(Message msg);

    /**
     * 동의서 일괄 전자서명
     * @param msg
     */
    protected abstract void processConsentSignReq(Message msg);

}
