import React, { Component } from 'react';
import ReactDOM from 'react-dom';

import axios from 'axios';
import Snackbar from 'material-ui/Snackbar';
import Fade from 'material-ui/transitions/Fade';

import update from 'immutability-helper'

import Dialog, {
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
} from 'material-ui/Dialog';

import Button from 'material-ui/Button';

import EvaluateSuccessEffectDisplay from './EvaluateSuccessEffectDisplay'

import _ from 'lodash'

/*
	若干js库
	http://inorganik.github.io/countUp.js/

*/
/*
	切下一关需要更新:
	LeftViewContainer state.gameAnswer
*/

import TPIContext from './TPIContext'
import { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER
    , EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC } from 'educoder'
import { MuiThemeProvider, createMuiTheme, withStyles } from 'material-ui/styles';
import MUIDialogStyleUtil from '../modules/page/component/MUIDialogStyleUtil'

const styles = MUIDialogStyleUtil.getTwoButtonStyle()

// 主题自定义
const theme = createMuiTheme({
  palette: {
    primary: { 
    	main: '#4CACFF',
    	contrastText: 'rgba(255, 255, 255, 0.87)'
	}, 
    secondary: { main: '#4CACFF' }, // This is just green.A700 as hex.
  },
});

const testSetsExpandedArrayInitVal = [false, false, false, false, false, 
									 false, false, false, false, false, 
									 false, false, false, false, false, 
									 false, false, false, false, false]
window.__fetchAllFlag = false;	//  是否调用过fetchAll   TODO 如何多次使用provider?

const $ = window.$
class TPIContextProvider extends Component {
	constructor(props) {
		super(props)
		this.onRunCodeTestFinish = this.onRunCodeTestFinish.bind(this)
		this.onRunChooseTestFinish = this.onRunChooseTestFinish.bind(this)
		this.testSetUnlock = this.testSetUnlock.bind(this)

		this.onTestSetHeaderClick = this.onTestSetHeaderClick.bind(this)

		this.onShowPrevStage = this.onShowPrevStage.bind(this)
		this.onShowNextStage = this.onShowNextStage.bind(this)

		this.readGameAnswer = this.readGameAnswer.bind(this)
		this.praisePlus = this.praisePlus.bind(this)
		
		this.onGamePassed = this.onGamePassed.bind(this)

		this.onPathChange = this.onPathChange.bind(this)

		this.showSnackbar = this.showSnackbar.bind(this)
		this.showDialog = this.showDialog.bind(this)

		this.onShowUpdateDialog = this.onShowUpdateDialog.bind(this)
		this.updateDialogClose = this.updateDialogClose.bind(this)
		
		// this.showEffectDisplay();

		this.state = {
			loading: true,	// 正在加载数据
			gDialogOpen: false,
			currentGamePassed: false,	// 当前game评测通过
			currentPassedGameGainGold: 0, 	// 当前通过的game获得的金币数
			currentPassedGameGainExperience: 0,	// 当前通过的game获得的经验数

			user: {},
			challenge: {},
			shixun_name: '',
			hide_code: false,

			showUpdateDialog: false,

			testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0),
		}
	}

	showEffectDisplay = (data) => {
		const dom = document.getElementById('picture_display');
		window.$(dom).show();
		ReactDOM.unmountComponentAtNode(dom)
  		ReactDOM.render(<EvaluateSuccessEffectDisplay type={"qrcode"} {...data} />, dom);
	}

	onShowUpdateDialog() {
		this.setState({showUpdateDialog: true})
	}
	// updateNowSuccess true 立即更新成功
	// TODO updateDialogClose方法名不对, 改为updateDialogCallback
	updateDialogClose(nextUpdateSuccess, updateNowSuccess) {
		const { myshixun } = this.state;
		if (nextUpdateSuccess) {
			myshixun.system_tip = true;
		}
		let { tpm_cases_modified, tpm_modified, tpm_script_modified } = this.state;
		if (updateNowSuccess) {
			tpm_cases_modified = false;
			tpm_modified = false;
			tpm_script_modified = false;
		}
		this.setState({
			myshixun,
			tpm_cases_modified,
			tpm_modified,
			tpm_script_modified,
			showUpdateDialog: false
		})
	}

	componentWillUnmount() {
		this.costTimeInterval && window.clearInterval(this.costTimeInterval)
	}
	componentDidMount() {

		// TODO 登录状态的判断?
		// request
        // var shixunId = this.props.match.params.shixunId;
        var stageId = this.props.match.params.stageId;
        
		window.__fetchAllFlag = false;
		this.fetchAll(stageId);

		this.costTimeInterval = window.setInterval(()=> {
			const { game } = this.state;
			if (!game || game.status === 2) { // 已完成的任务不需要计时
				return;
			}
			if (game.cost_time || game.cost_time === 0) {
				// game.cost_time += 1;
				this.setState({
					game: update(game, {cost_time: { $set: (game.cost_time+1) }})
				})
			}
		}, 1000)

		// 页面离开时存下用户的任务耗时

		window.$(window).unload( ()=>{
            this._updateCostTime();
		});
	}
	// force 评测通过后,异步执行该方法,强制同步costTime到服务端
	_updateCostTime(async = false, force) {
		const { game, loading } = this.state;
		// TODO 还有一种情况,通关后cost_time计时停止,没法通过这个判断
        if (!force && (loading || !game || game.status === 2)) {
        	return; // 已完成的任务不需要处理
        }
		let testPath = ''
		if (window.location.port == 3007) {
			testPath = 'http://pre-newweb.educoder.net'
		}
		// var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time`
		var url = `${testPath}/api/tasks/${ game.identifier }/cost_time`
	    window.$.ajax({
	        type: 'get',
	        url: url,
	        async: async, //IMPORTANT, the call will be synchronous
	        data: {
                time: game.cost_time
	        }
	    }).done((data) => {
	        console.log('complete');
	    });
	}

	onGamePassed(passed) {
		const { game } = this.state
		// 随便给个分,以免重新评测时又出现评星组件(注意:目前game.star没有显示在界面上,如果有则不能这么做)
		// game.star = 6; 
		this.setState({
			game: update(game, {star: { $set: 6 }}),
			currentGamePassed: !!passed
		})
	}
	onTestSetHeaderClick(index) {
		// let { testSetsExpandedArray } = this.state;
		let testSetsExpandedArray;
		// 一次只打开一个
		if (this.state.testSetsExpandedArray[index] === false) {
			testSetsExpandedArray = testSetsExpandedArrayInitVal.slice(0);
		} else {
			testSetsExpandedArray = this.state.testSetsExpandedArray.slice(0);
		}
		testSetsExpandedArray[index] = !testSetsExpandedArray[index];
		this.setState({
			testSetsExpandedArray,
		})
	}

	onShowPrevStage() {

	}
	onShowNextStage() {
		window.__fetchAllFlag = false;
		console.log('onShowNextStage.........')
		// this.fetchAll('vznhx7mctwfq')
	}

	componentWillReceiveProps(newProps, oldProps) {
		var newStageId = newProps.match.params.stageId;
		if (!this.props || newStageId !== this.props.match.params.stageId) {
			window.__fetchAllFlag = false;
			this.fetchAll(newStageId)
		}
	}


	// praise_tread/praise_plus?obj_id=569&obj_type=Challenge&horizontal=true&game_praise=true
	/*
		TODO 旧的接口在未登录时的返回值
		//获取登录页面地址
var signinPath = '/';
var htmlvalue = '<div class="task-popup" style="width:480px;"><div class="task-popup-title clearfix"><h3 class="fl color-grey3">提示</h3></div>'+
        '<div class="task-popup-content"><p class="task-popup-text-center font-16 mt10 mb10">您还没有登录,请登录后再执行此操作,谢谢!</p></div><div class="task-popup-right-sure clearfix">'+
        '<a href="javascript:void(0);" onclick="hideModal();" class="task-btn">取消</a><a href="' + signinPath + '" class="task-btn task-btn-orange ml15">登录</a></div></div>';
pop_box_new(htmlvalue, 480, 182);
	*/
	praisePlus() {
		const { challenge, game } = this.state;
		let praise = true;
		const url = `/tasks/${game.identifier}/plus_or_cancel_praise.json`
		// const url = `/praise_tread/praise_plus?obj_id=${challenge.id}&obj_type=Challenge&horizontal=${praise}&game_praise=true`
		axios.post(url)
		  .then((response) => {

			    if (response.data) {
			    	const { praise_count, praise } = response.data;
			    	// challenge.praise_count = praise_tread_count;
			    	// challenge.user_praise = praise;
			    	this.setState({ challenge: update(challenge, 
			    		{
			    			praise_count: { $set: praise_count },
			    			user_praise:  { $set: praise },
			    		})
			    	})
			    }
		    
		  	})
		  	.catch(function (error) {
		    	console.log(error);
		  	});
	}

	onPathChange(index) {
		let { challenge } = this.state;
		// challenge = Object.assign({}, challenge)
		// challenge.pathIndex = index;
		this.setState({
			challenge: update(challenge, {pathIndex: { $set: index }}),
		})
		// TODO load new path content
	}

	updateChallengePath = (path) => {
		const challenge = this.state.challenge;
		if (challenge.path === path) {
			return;
		}
		const { myshixun } = this.state;
		// myshixun.system_tip = false;
		

		challenge.path = path;
		const newChallenge = this.handleChallengePath(challenge);
		this.setState({ challenge: newChallenge, 
			myshixun: update(myshixun, {system_tip: { $set: false }}),
		})
	}

	handleChallengePath(challenge) {
		if (challenge.path && typeof challenge.path === "string") {		// 多path的处理
  			let path = challenge.path.split(';');
  			_.remove(path, (item)=> !item)
  			if (path.length > 1) {
	  			challenge.path = path;
	  			challenge.multiPath = true;
  			} else {
  				challenge.path = challenge.path.replace(';', '').trim()	// 多path 改为单path 出现了  aaa.java;的情况
  				challenge.multiPath = false;
  			}
  		}
  		challenge.pathIndex = 0;
  		return challenge;
	}

	newResData2OldResData(newResData) {
		newResData.latest_output = newResData.last_compile_output
		// newResData.power 
		newResData.record = newResData.record_onsume_time

		// 老版用的hide_code
		newResData.hide_code = newResData.shixun.hide_code;

		newResData.image_url = newResData.user.image_url
		newResData.grade = newResData.user.grade
		newResData.user_url = newResData.user.user_url
		newResData.username = newResData.user.name

		newResData.output_sets = {}
		// newResData.output_sets.had_test_count = newResData.test_sets_count
		newResData.output_sets.test_sets = newResData.test_sets 	// JSON.stringify()
		newResData.output_sets.test_sets_count = newResData.test_sets_count
		// newResData.output_sets.had_passed_testsests_error_count = newResData.sets_error_count
		newResData.output_sets.had_passed_testsests_error_count = newResData.test_sets_count 
				- newResData.sets_error_count
		//			allowed_hidden_testset
		//			sets_error_count
		//			test_sets_count
		//			test_sets
		// had_passed_testsests_error_count
		//			test_sets
		//			test_sets

		return newResData
	}
	// 将若干数据重新组织一下
	_handleResponseData(resData_arg) {
		const resData = this.newResData2OldResData(Object.assign({}, resData_arg))
	    let challenge = resData.challenge;
	    challenge.isHtml = false;
  		challenge.isWeb = false;
  		challenge.isAndroid = false;
  		challenge.showLanguagePictrue = false;
  		challenge.hasAnswer = resData.has_answer;

	    let output_sets = resData.output_sets;
		if (resData.st === 0) {		// 代码题
	    	challenge = this.handleChallengePath(challenge)
	  		
	  		const mirror_name = (resData.mirror_name && resData.mirror_name.join) 
	  				? resData.mirror_name.join(';') : (resData.mirror_name || '');
	  		if (mirror_name.indexOf('Html') !== -1) {
	  			challenge.isHtml = true;
	  			challenge.showLanguagePictrue = true;
	  		} else if (mirror_name.indexOf('Web') !== -1 || mirror_name.indexOf('JFinal') !== -1) {
	  			challenge.isWeb = true;
	  		} else if (mirror_name.indexOf('Android') !== -1) {
	  			challenge.isAndroid = true;
	  		} 

	  		if (output_sets && output_sets.test_sets && typeof output_sets.test_sets == 'string') {
	  			const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
	  			output_sets.test_sets_array = test_sets_array;
	  		} else {
	  			output_sets.test_sets_array = output_sets.test_sets
	  		}

	    } else {		// 选择题
	    	// 选择题题干markdown初始化
	    	const $ = window.$
			window.setTimeout(()=>{
				var lens = $("#choiceRepositoryView textarea").length;
				
		        for(var i = 1; i <= lens; i++){
		            window.editormd.markdownToHTML("choose_subject_" + i, {
		                htmlDecode: "style,script,iframe",  // you can filter tags decode
		                taskList: true,
		                tex: true,  // 数学公式
		                // flowChart: true,  // 默认不解析
		                // sequenceDiagram: true // 默认不解析
		            });
		        }
	        }, 400)
	    }
	    challenge.user_praise = resData.user_praise;
	    challenge.praise_count = resData.praise_count;
	    challenge.showWebDisplayButton = false;
    	resData.challenge = challenge;

	    // 将一些属性写到game上
  		let game = resData.game;
  		game.prev_game = resData.prev_game;
  		game.next_game = resData.next_game;
		if (game.status == 2) {
			// 已通关
			game.isPassThrough = true
		}
  		resData.game = game;
		

  		const { tpm_cases_modified, tpm_modified, tpm_script_modified, myshixun } = resData;
  		if (myshixun.system_tip) {
			// system_tip为true的时候 不弹框提示用户更新
  			resData.showUpdateDialog = false
  		} else {
  			let needUpdateScript = (tpm_modified || tpm_script_modified) && challenge.st === 0;
  			resData.showUpdateDialog = needUpdateScript || tpm_cases_modified 
  		}

		/**
		email: "721773699@qq.com"
		grade: 213996
		identity: 1
		image_url: "avatars/User/1"
		login: "innov"
		name: "Coder"
		user_url: "/users/innov"
		 */
	    let user = resData.user;
  		user.username = resData.user.name;
  		user.user_url = `/users/${resData.user.login}`;
  		// user.image_url = resData.image_url;
  		user.is_teacher = resData.is_teacher;
  		resData.user = user;
  		this._handleUserAuthor(resData)
  		// TODO  测试
  		// resData.power = 0;

	    this.setState({
    		...resData,

    		currentGamePassed: false,
    		loading: false,
    		testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0),
    	})

	    window.document.title = resData.shixun.name

	    window.__myshixun = resData.myshixun;		// tpi_html_show需要用到
	}
	_handleUserAuthor(resData) {
		// tpi tpm权限控制
		// const EDU_ADMIN = 1       // 超级管理员
		// const EDU_SHIXUN_MANAGER = 2 // 实训管理员
		// const EDU_SHIXUN_MEMBER = 3  // 实训成员
		// const EDU_CERTIFICATION_TEACHER = 4 // 平台认证的老师
		// const EDU_GAME_MANAGER = 5     // TPI的创建者
		// const EDU_TEACHER = 6 // 平台老师,但是未认证
		// const EDU_NORMAL = 7  // 普通用户


		/** 
		    EDU_ADMIN = 1       # 超级管理员
			EDU_BUSINESS = 2    # 运营人员
			EDU_SHIXUN_MANAGER = 3 # 实训管理员
			EDU_SHIXUN_MEMBER = 4  # 实训成员
			EDU_CERTIFICATION_TEACHER = 5 # 平台认证的老师
			EDU_GAME_MANAGER = 6     # TPI的创建者
			EDU_TEACHER = 7 # 平台老师,但是未认证
			EDU_NORMAL = 8  # 普通用户
		*/ 

		// myshixun_manager power is_teacher
		resData.power = 0
		resData.myshixun_manager = false
		// resData.is_teacher = false

		if (resData.user.identity === EDU_ADMIN) {
			resData.power = 1
			resData.myshixun_manager = true
		} else if (resData.user.identity === EDU_BUSINESS) {
			resData.power = 1
			resData.myshixun_manager = true
		} else if (resData.user.identity === EDU_SHIXUN_MANAGER) {
			resData.power = 1
			resData.myshixun_manager = true
		} else if (resData.user.identity === EDU_SHIXUN_MEMBER) {
			resData.power = 1
			resData.myshixun_manager = true
		} else if (resData.user.identity === EDU_CERTIFICATION_TEACHER) {
			resData.power = 1
			// 已认证老师允许跳关
			resData.myshixun_manager = true
			// resData.is_teacher = true

		} else if (resData.user.identity === EDU_TEACHER) {
			// resData.is_teacher = true
		} else if (resData.user.identity === EDU_NORMAL) {
			
		} 
		return resData
	}

	fetchAll(stageId, noTimeout) {

		if (window.__fetchAllFlag == true ) {
			console.log('TPIContextProvider call fetchAll repeatly!')
			return;
		}
		// 切换关卡的时候,同步costTime
		this._updateCostTime(true);

		if (!stageId) {
			// stageId = 'zl6kx8f7vfpo';
			// http://localhost:3000/myshixuns/so5w6iap97/stages/zl6kx8f7vfpo
		}

		// var url = `/api/v1/games/${stageId}`
		var url = `/tasks/${stageId}.json`
		
		// {"status":1,"message":"undefined method `authenticate!' for #<Grape::Endpoint:0xc8c91c0>"}
		window.__fetchAllFlag = true;


		this.setState({
	    	loading: true,
	    	currentGamePassed: false,  // 切换game时重置passed字段
	    })
		
		// test
		// var data = {"st":0,"discusses_count":0,"game_count":3,"record_onsume_time":0.36,"prev_game":null,"next_game":"7p9xwo2hklqv","praise_count":0,"user_praise":false,"time_limit":20,"tomcat_url":"http://47.96.157.89","is_teacher":false,"myshixun_manager":true,"game":{"id":2192828,"myshixun_id":580911,"user_id":57844,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:51:05.000+08:00","status":2,"final_score":0,"challenge_id":10010,"open_time":"2019-09-03T15:50:49.000+08:00","identifier":"hknvz4oaw825","answer_open":0,"end_time":"2019-09-03T15:51:04.000+08:00","retry_status":0,"resubmit_identifier":null,"test_sets_view":false,"picture_path":null,"accuracy":1.0,"modify_time":"2019-09-03T15:23:33.000+08:00","star":0,"cost_time":14,"evaluate_count":1,"answer_deduction":0},"challenge":{"id":10010,"shixun_id":3516,"subject":"1.1 列表操作","position":1,"task_pass":"[TOC]\n\n---\n\n####任务描述\n\n\n数据集a包含1-10共10个整数,请以a为输入数据,编写python程序,实现如下功能:\n①\t用2种方法输出a中所有奇数\n②\t输出大于3,小于7的偶数\n③\t用2种方法输出[1,2,3,…10,11,…20]\n④\t输出a的最大值、最小值。\n⑤\t用2种方法输出[10,9,…2,1]\n⑥\t输出[1,2,3,1,2,3,1,2,3,1,2,3]\n\n\n####相关知识\n\n\n请自行学习相关知识\n\n\n---\n开始你的任务吧,祝你成功!","score":100,"path":"1-1-stu.py","st":0,"web_route":null,"modify_time":"2019-09-03T15:23:33.000+08:00","exec_time":20,"praises_count":0},"shixun":{"id":3516,"name":"作业1——Python程序设计","user_id":77620,"gpid":null,"visits":23,"created_at":"2019-09-03T14:18:17.000+08:00","updated_at":"2019-09-03T15:58:16.000+08:00","status":0,"language":null,"authentication":false,"identifier":"6lzjig58","trainee":1,"major_id":null,"webssh":2,"homepage_show":false,"hidden":false,"fork_from":null,"can_copy":true,"modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","publish_time":null,"closer_id":null,"end_time":null,"git_url":null,"vnc":null,"myshixuns_count":3,"challenges_count":3,"use_scope":0,"mirror_script_id":20,"image_text":null,"code_hidden":false,"task_pass":true,"exec_time":20,"test_set_permission":true,"sigle_training":false,"hide_code":false,"multi_webssh":false,"excute_time":null,"repo_name":"p09218567/6lzjig58","averge_star":5.0,"opening_time":null,"users_count":1,"forbid_copy":false,"pod_life":0},"myshixun":{"id":580911,"shixun_id":3516,"is_public":true,"user_id":57844,"gpid":null,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:59:04.000+08:00","status":0,"identifier":"k36hm4rwav","commit_id":"f25e1713882156480fc45ce0af57eff395a5037f","modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","system_tip":false,"git_url":null,"onclick_time":"2019-09-03T15:50:49.000+08:00","repo_name":"p53276410/k36hm4rwav20190903155049"},"user":{"user_id":57844,"login":"p53276410","name":"文振乾","grade":24624,"identity":1,"image_url":"avatars/User/57844","school":"EduCoder团队"},"tpm_modified":true,"tpm_cases_modified":false,"mirror_name":["Python3.6"],"has_answer":false,"test_sets":[{"is_public":true,"result":true,"input":"","output":"result of a:\n[1, 3, 5, 7, 9]\n[1, 3, 5, 7, 9]\nresult of b:\n[2, 4, 6, 8, 10]\nresult of c:\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\nresult of d:\nThe minimum is:1\nThe maxium is:10\nresult of e:\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nresult of f:\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\n","actual_output":"result of a:\r\n[1, 3, 5, 7, 9]\r\n[1, 3, 5, 7, 9]\r\nresult of b:\r\n[2, 4, 6, 8, 10]\r\nresult of c:\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\nresult of d:\r\nThe minimum is:1\r\nThe maxium is:10\r\nresult of e:\r\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\r\nresult of f:\r\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\r\n","compile_success":1,"ts_time":0.05,"ts_mem":8.77}],"allowed_unlock":true,"last_compile_output":"compile successfully","test_sets_count":1,"sets_error_count":0}
		// data.test_sets[0].actual_output = data.test_sets[0].actual_output.replace(/\r\n/g, '\n')
		// data.test_sets[0].output = data.test_sets[0].output.replace(/\r\n/g, '\n')
		// console.log(JSON.stringify(data))
		// data.shixun.vnc = true
		// data.vnc_url= "http://47.96.157.89:41158/vnc_lite.html?password=headless"

		// this._handleResponseData(data)
		// return 

		axios.get(url, {
				// https://stackoverflow.com/questions/48861290/the-value-of-the-access-control-allow-origin-header-in-the-response-must-not-b
    			// withCredentials: true,
    		})
		  .then((response) => {
			    // {"status":1,"message":"Unauthorized. \u7528\u6237\u8ba4\u8bc1\u5931\u8d25."}

				window.__fetchAllFlag = false;

			    if (response.data.status == 403) {
					window.location.href = "/403";
			    	return;
			    }
			    if (response.data.status == 404) {
					// 如果第一次发生404,则隔1s后再调用一次本接口;(因为ucloud主从同步可能有延迟)	
					if (!noTimeout) {
						setTimeout(() => {
							this.fetchAll(stageId, true)
						}, 1000)
						return;
					}
			    	window.location.href = '/myshixuns/not_found'
			    	return;
			    }

			    this._handleResponseData(response.data)
		    
		  	})
		  	.catch(function (error) {
		    	console.log(error);
		  	});
	
	}

	readGameAnswer(resData) {
		// game.final_score = resData.final_score;
		if (resData.final_score) {
			var game = this.state.game;
			this.setState({
				game: update(game, {final_score: { $set: resData.final_score }}),
				grade: resData.grade
			})
		} else {
			this.setState({
				grade: resData.grade
			})
		}
		
	}
	closeTaskResultLayer() {
		this.setState({
			game: (this.state.game.status == 2 ? update(this.state.game, {
				isPassThrough: { $set: true },
			}) : this.state.game) ,
			currentGamePassed: false
		})
	}
	onRunChooseTestFinish(response) {
		const { test_sets, challenge_chooses_count, choose_correct_num, grade, experience, gold, had_submmit, next_game } = response;
		response.had_submmit = true; // 是否已提交
		const { game } = this.state;
		let currentGamePassed = false
		if (challenge_chooses_count === choose_correct_num) {
			game.status = 2;
			// game.isPassThrough = true
			game.next_game = next_game;

			currentGamePassed = true;

			
			this._updateCostTime(true, true);
		}
		this.setState({
			choose_test_cases: response,
			grade: grade,

			game,
			next_game,
			currentGamePassed: currentGamePassed,
			currentPassedGameGainGold: gold,
			currentPassedGameGainExperience: experience,
		})
	}	
	initDisplayInterval = () => {
		const challenge = this.state.challenge
		if (this.showWebDisplayButtonTimeout) {
			window.clearTimeout(this.showWebDisplayButtonTimeout)
		}
		this.showWebDisplayButtonTimeout = window.setTimeout(() => {
			this.setState({ challenge: update(challenge, 
				{
					showWebDisplayButton: { $set: false },
				})
			})
			this.showWebDisplayButtonTimeout = null
		}, 61 * 1000)

		let remain = 60
		if (this.displayInterval) {
			window.clearInterval(this.displayInterval)
		}
		this.displayInterval = window.setInterval(() => {
			const button = $('#showWebDisplayButton');
			if (button.length) {
				button.html(`查看效果(${remain})`)
				if (remain == 0) {
					button.html('查看效果')
				}
			}
			if (remain == 0) {
				window.clearInterval(this.displayInterval)
				this.displayInterval = null
				return;
			}
			
			remain -= 1;
		}, 1000)
	}
	language_display(data) {
		const { game, tomcat_url } = this.state;
		const challenge = Object.assign({}, this.state.challenge)
		if(challenge.isWeb && data.port != -1) {
            // var $result = $("#php_display");
            challenge.showWebDisplayButton = true;	// ActionView处是否出现查看效果按钮
			this.initDisplayInterval()

            const path = challenge.web_route || challenge.path
            const webDisplayUrl = `${tomcat_url}:${data.port}/${path}`
            challenge.webDisplayUrl = webDisplayUrl
            challenge.showLanguagePictrue = true;	// 评测通过弹出层是否出现查看效果按钮
        }
		// else if(challenge.isAndroid && data.picture != 0){
        // 	// https://www.educoder.net/shixuns/qrcode?game_id=218589&_=1525571882782
        //     $.ajax({
        //         url: `/shixuns/qrcode?game_id=${game.id}`,
        //         dataType: 'script'
        //     });
        //     challenge.showLanguagePictrue = true;
        // }
		else if(data.picture != 0){
        	// 对应服务端erb文件为  _picture_display.html.erb
            // $.ajax({
            //     url: "/users/picture_show?game_id="+data.picture,
            //     cache: false,
            //     dataType: 'script'
            // });

			/**
				{
					"type": "image",
					"orignal_picture": [],
					"user_picture": [],
					"answer_picture": []
				}
			 */
			const url = `/tasks/${game.identifier}/picture_display.json`
			axios.get(url)
		  		.then((response) => {
					// response.data.type qrcode_str
					this.showEffectDisplay(response.data)
				})

            challenge.showLanguagePictrue = true;
        }
        this.setState({
        	challenge
        })
	}
	onRunCodeTestFinish(response) {
		console.log('onRunCodeTestFinish', response)
		const { test_sets, test_sets_count, test_sets_hidden_count, test_sets_public_count
			, had_test_count, had_passed_testsests_error_count, had_passed_testsests_hidden_count
			, had_passed_testsests_public_count, final_score, gold, experience, latest_output, status
			, had_done, score, tag_count, power, record, next_game, grade, picture,
			sets_error_count, last_compile_output, record_consume_time} = response;

		const { game } = this.state;

		const currentGamePassed = this.props.game !== 2 && status === 2

		

		// 评测通过了,立即同步costTime
		currentGamePassed && this._updateCostTime(true, true);


		const output_sets = {
			"test_sets": test_sets,
			"test_sets_array": test_sets,
	        "had_test_count": had_test_count || test_sets_count,
	        "test_sets_count": test_sets_count,
	        // "had_passed_testsests_error_count": had_passed_testsests_error_count,
	        "had_passed_testsests_error_count": test_sets_count - sets_error_count,
	        "test_sets_hidden_count": test_sets_hidden_count,
	        "test_sets_public_count": test_sets_public_count,
	        "had_passed_testsests_hidden_count": had_passed_testsests_hidden_count,
	        "had_passed_testsests_public_count": had_passed_testsests_public_count
		};
		// if (output_sets && output_sets.test_sets) {
  		// 	const test_sets_array = JSON.parse("[" + output_sets.test_sets + "]");
  		// 	output_sets.test_sets_array = test_sets_array;
  		// }
		
		//   检查是否编译通过
		let compileSuccess = false;
		if (test_sets && test_sets.length) {
			test_sets.some((item) => {
				if (item.compile_success) {
					compileSuccess = true;
					return true;
				}
			})
		}

		compileSuccess && this.language_display(response);
		if (currentGamePassed) {
			game.status = 2;
			// game.isPassThrough = true
			game.next_game = next_game;	
		} else {
			this.showDialog({
				contentText: <div>
					<div>评测未通过</div>
					<div>详情请参见“测试结果”</div>
				</div>,
				isSingleButton: true
			})
		}
		

		this.setState({
			testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0), // 重置测试集展开状态
			currentGamePassed,
			currentPassedGameGainGold: gold,
			currentPassedGameGainExperience: experience,

			output_sets,
			game,
			next_game,
			
			latest_output: last_compile_output,
			record: record_consume_time,
			grade,
			had_done,
			
		})
	}
	resetTestSetsExpandedArray = () => {
		this.setState({
			testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0), // 重置测试集展开状态
		})
	}

	testSetUnlock() {
		const { game, challenge } = this.state;
		const url = `/tasks/${game.identifier}/check_test_sets.json`
		axios.get(url, {
    			// withCredentials: true,
    		})
		  .then((response) => {
				// TODO status -2 重复操作,直接解锁
			    if (response.data.test_sets == -1) {
			    	console.error('testSetUnlock失败!')
			    	this.showSnackbar(response.data.message)
			    	return;
			    } else {
			    	// 被扣除的金币,是负数
			    	const deltaScore = -challenge.score * 5;
					// output_sets
					let { output_sets } = this.state;
					output_sets = Object.assign({}, output_sets);
					// const test_sets_array = JSON.parse("[" + response.data.test_sets + "]");
	  				output_sets.test_sets_array = response.data.test_sets;
			    	this.setState({ 
						output_sets: output_sets,
			    		grade: this.state.grade + deltaScore,
			    		game : update(game, {test_sets_view: { $set: true }}), 
			    		testSetsExpandedArray: testSetsExpandedArrayInitVal.slice(0) 
			    	})
			    	this.handleGdialogClose();
			    }
		    
		  	})
		  	.catch(function (error) {
		    	console.log(error);
		  	});
	}

	handleSnackbarClose() {
		this.setState({
			snackbarOpen: false,
			snackbarVertical: '',
			snackbarHorizontal: '',
		})
	}
	// 全局的snackbar this.props.showSnackbar调用即可
	showSnackbar(text, vertical, horizontal) {
		this.setState({
			snackbarOpen: true,
			snackbarText: text,
			snackbarVertical: vertical,
			snackbarHorizontal: horizontal,
		})
	}

	/* 
        TODO 写成HOC组件,更好复用
		全局的Dialog this.props.showDialog调用即可
		@param contentText  dialog显示的提示文本 
		@param callback 	确定按钮回调方法
		@param moreButtonsRender  除了“确定”、“取消”按钮外的其他按钮
		@param okButtonText  “确定”按钮显示文本,如 继续查看
	*/
	showDialog(params) {
		const { contentText, callback, moreButtonsRender, okButtonText, isSingleButton } = params;

		this.dialogOkCallback = callback;
		this.moreButtonsRender = moreButtonsRender
		this.okButtonText = okButtonText;
		this.isSingleButton = isSingleButton;
		this.setState({
			gDialogOpen: true,
			gDialogContentText: contentText
		})
	}
	onGdialogOkBtnClick() {

		this.dialogOkCallback && this.dialogOkCallback();
		// this.setState({
		// 	gDialogOpen: true
		// })
	}
	handleGdialogClose = () => {
		this.setState({
			gDialogOpen: false
		})
	}
	render() {
		const { classes } = this.props;
		return (
				<TPIContext.Provider
					value={{
						...this.props,
						...this.state,
						resetTestSetsExpandedArray: this.resetTestSetsExpandedArray,
						onRunCodeTestFinish: this.onRunCodeTestFinish,
						onRunChooseTestFinish: this.onRunChooseTestFinish,
						testSetUnlock: this.testSetUnlock,

						onTestSetHeaderClick: this.onTestSetHeaderClick,

						readGameAnswer: this.readGameAnswer,

						onShowPrevStage: this.onShowPrevStage,
						onShowNextStage: this.onShowNextStage,

						praisePlus: this.praisePlus,
						onGamePassed: this.onGamePassed,
						closeTaskResultLayer: () => this.closeTaskResultLayer(),

						onPathChange: this.onPathChange,
						updateChallengePath: this.updateChallengePath,

						showSnackbar: this.showSnackbar,
						showDialog: this.showDialog,
						handleGdialogClose: () => this.handleGdialogClose(),

						onShowUpdateDialog: this.onShowUpdateDialog,
						updateDialogClose: this.updateDialogClose,

						match: this.props.match
					}}
				>	
					<Dialog
						id="tpi-dialog"
			          	open={this.state.gDialogOpen}
						disableEscapeKeyDown={true}
			          	onClose={() => this.handleGdialogClose()}
			        >	
				       	<DialogTitle id="alert-dialog-title">{"提示"}</DialogTitle>
			          	<DialogContent id="dialog-content">
				            <DialogContentText id="alert-dialog-description" style={{textAlign: 'center'}}>
					        	{this.state.gDialogContentText}
				            </DialogContentText>
			          	</DialogContent>
						  {/* mb20 加了有样式问题 */}
			          	<DialogActions className={""} id="dialog-actions">
										{ this.isSingleButton ? <div className="task-popup-submit clearfix"
														style={{ textAlign: 'center', 'margin-bottom': '14px'}}>
													<a  className="task-btn task-btn-orange"
														onClick={this.handleGdialogClose}
													>知道啦</a>
												</div> :
										<React.Fragment>
											<Button onClick={() => this.handleGdialogClose()} color="primary" 
													className={`${classes.button} ${classes.buttonGray} ${classes.borderRadiusNone}`}>
												关闭
											</Button>
											<Button variant="raised" className={`${classes.button} ${classes.borderRadiusNone}`}
													onClick={() => this.onGdialogOkBtnClick() } color="primary" autoFocus>
														{ this.okButtonText ? this.okButtonText : '确定' }
											</Button>
										</React.Fragment>	}									
										{this.moreButtonsRender && this.moreButtonsRender()}
			          	</DialogActions>
			        </Dialog>

					<Snackbar
						className={"rootSnackbar"}
			          	open={this.state.snackbarOpen}
			          	autoHideDuration={3000}
			          	anchorOrigin={{ vertical: this.state.snackbarVertical || 'top'
			          			, horizontal: this.state.snackbarHorizontal || 'center' }}
			          	onClose={() => this.handleSnackbarClose()}
			          	transition={Fade}
			          	SnackbarContentProps={{
			            	'aria-describedby': 'message-id',
			          	}}
			          	resumeHideDuration={2000}
			        	message={<span id="message-id">{this.state.snackbarText}</span>}
			        />
					{this.props.children}
				</TPIContext.Provider>
		)
	}
}

export default  CNotificationHOC() (withStyles(styles) (TPIContextProvider));