"""Problem XBlock, and friends."""

import json

from .core import XBlock, register_view, register_handler, Object, Scope, List, String
from .util import call_once_property
from .widget import Widget
from webob import Response


class ProblemBlock(XBlock):

    checker_arguments = Object(help="Map of checker names to `check` arguments", scope=Scope.content, default={})
    children_names = List(help="List of names for child elements", scope=Scope.content, default=[])
    has_children = True

    # The content controls how the Inputs attach to Graders
    @register_view("student_view")
    def student_view(self, context):
        result = Widget()
        child_widgets = [self.runtime.render_child(child, context, "problem_view") for child in self.children]
        result.add_widgets_resources(child_widgets)
        result.add_content(self.runtime.render_template("problem.html",
            named_children=zip(self.children_names, child_widgets))
        )
        result.add_javascript("""
            function ProblemBlock(runtime, element) {

                var handler_url = runtime.handler_url('check')
                $(element).bind('ajaxSend', function(elm, xhr, s) {
                    runtime.prep_xml_http_request(xhr);
                });

                function update_checkers() {}

                $(element).find('.check').bind('click', function() {
                    var data = {};
                    for (var i = 0; i < runtime.children.length; i++) {
                        var child = runtime.children[i];
                        var name = $(child.element).closest('.problem-child').data('name');
                        if (typeof child.submit == 'function') {
                            data[name] = runtime.children[i].submit();
                        } else {
                            data[name] = null;
                        }
                    }
                    $.post(handler_url, JSON.stringify(data)).success(update_checkers);
                });
            }
            """)
        result.initialize_js('ProblemBlock')
        return result

    @call_once_property
    def child_name_map(self):
        return dict(zip(self.children_names, self.children))

    @register_handler("check")
    def check_answer(self, request):
        submissions = json.loads(request.body)

        for input_name, submission in submissions.items():
            self.child_name_map[input_name].submit(submission)

        results = {}
        for checker, arguments in self.checker_arguments:
            for arg_name, arg_value in arguments.items():
                if isinstance(arg_value, dict) and arg_value.get('_type') == 'reference':
                    child, _, attribute = arg_value['ref_name'].partition('.')
                    arguments[arg_name] = getattr(self.child_name_map[child], attribute)
            results[checker] = self.child_name_map[checker].check(**arguments)

        return Response(json.dumps(results))


class InputBlock(XBlock):

    def submit(self, submission):
        """
        Called with the result of the javascript Block's submit() function.
        """
        pass

class CheckerBlock(XBlock):
    pass


class TextInputBlock(InputBlock):

    student_input = String(help="Last input submitted by the student", default="", scope=Scope.student_state)

    @register_view("student_view")
    def student_view(self, context):
        return Widget("<p>I can only appear inside problems.</p>")

    @register_view("problem_view")
    def problem_view(self, context):
        result = Widget("<input type='text' name='input' value='%s'>" % self.student_input)
        result.add_javascript("""
            function TextInputBlock(runtime, element) {
                return {
                    submit: function() {
                        return $(element).find(':input').serializeArray();
                    }
                }
            }
            """)
        result.initialize_js('TextInputBlock')
        return result

    def submit(self, submission):
        self.student_input = submission[0]['value']
@@ -465,10 +465,12 @@
 ult=
-%5B%5D
+None
 )%0A  
@@ -616,32 +616,170 @@
 self, context):%0A
+        if self.children_names is None:%0A            self.children_names = %5B%22unnamed_child_%25d%22 %25 idx for idx in range(len(self.children))%5D%0A
         result =
@@ -792,24 +792,30 @@
 t()%0A        
+named_
 child_widget
@@ -819,16 +819,36 @@
 gets = %5B
+%0A            (name, 
 self.run
@@ -896,26 +896,57 @@
 m_view%22)
- for child
+)%0A            for name, child%0A           
  in self
@@ -946,24 +946,30 @@
 in self.
+named_
 children
 %5D%0A      
@@ -960,16 +960,25 @@
 children
+%0A        
 %5D%0A      
@@ -1008,16 +1008,81 @@
 sources(
+widget for _, widget in named_child_widgets)%0A        print named_
 child_wi
@@ -1078,33 +1078,32 @@
 ed_child_widgets
-)
 %0A        result.
@@ -1190,33 +1190,14 @@
 ren=
-zip(self.children_
 name
-s, 
+d_
 chil
@@ -1205,18 +1205,16 @@
 _widgets
-))
 %0A       
@@ -1215,16 +1215,17 @@
        )
+)
 %0A       
@@ -2393,80 +2393,336 @@
 def 
-child_name_map(self):%0A        return dict(zip(self.children_names, self.
+named_children(self):%0A        if self.children_names is None:%0A            names = %5B%22unnamed_child_%25d%22 %25 idx for idx in range(len(self.children))%5D%0A        else:%0A            names = self.children_names%0A%0A        return zip(names, self.children)%0A%0A    @call_once_property%0A    def child_name_map(self):%0A        return dict(self.named_
 chil
@@ -2726,17 +2726,16 @@
 hildren)
-)
 %0A%0A    @r

Make unnamed children of problems get a default set of names so that state saving works