This is the routine to be called when you want to create
        the input files and related stuff with a plugin.
        
        :param tempfolder: a aiida.common.folders.Folder subclass where
                           the plugin should put all its files.
        :param inputdict: a dictionary with the input nodes, as they would
                be returned by get_inputdata_dict (without the Code!)

def _prepare_for_submission(self,tempfolder, inputdict):        
        """
        This is the routine to be called when you want to create
        the input files and related stuff with a plugin.
        
        :param tempfolder: a aiida.common.folders.Folder subclass where
                           the plugin should put all its files.
        :param inputdict: a dictionary with the input nodes, as they would
                be returned by get_inputdata_dict (without the Code!)
        """
        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError("No code specified for this "
                                       "calculation")

        try:
            parameters = inputdict.pop(self.get_linkname('parameters'))
        except KeyError:
            raise InputValidationError("No parameters specified for this "
                                       "calculation")
        if not isinstance(parameters, ParameterData):
            raise InputValidationError("parameters is not of type "
                                       "ParameterData")
        
        try:
            structure = inputdict.pop(self.get_linkname('structure'))
        except KeyError:
            raise InputValidationError("No structure specified for this "
                                       "calculation")
        if not isinstance(structure,StructureData):
            raise InputValidationError("structure node is not of type"
                                       "StructureData")
        
        try:
            settings = inputdict.pop(self.get_linkname('settings'),None)
        except KeyError:
            pass
        if settings is not None:
            if not isinstance(parameters, ParameterData):
                raise InputValidationError("parameters is not of type "
                                           "ParameterData")
        
        try:
            kpoints = inputdict.pop(self.get_linkname('kpoints'),None)
        except KeyError:
            pass
        if kpoints is not None:
            if not isinstance(kpoints, KpointsData):
                raise InputValidationError("kpoints is not of type KpointsData")
        
        ##############################
        # END OF INITIAL INPUT CHECK #
        ##############################
        
        # default atom getter: I will always retrieve the total energy at least
        default_atoms_getters = [ ["total_energy",""] ] 
        
        # ================================
        
        # save the structure in ase format
        atoms = structure.get_ase()
        atoms.write(tempfolder.get_abs_path(self._input_aseatoms))
        
        # ================== prepare the arguments of functions ================
        
        parameters_dict = parameters.get_dict()
        settings_dict = settings.get_dict() if settings is not None else {}
        
        # ==================== fix the args of the optimizer
        
        optimizer = parameters_dict.pop("optimizer",None)
        if optimizer is not None:
            # Validation
            if not isinstance(optimizer,dict):
                raise InputValidationError("optimizer key must contain a dictionary")
            # get the name of the optimizer
            optimizer_name = optimizer.pop("name",None)
            if optimizer_name is None:
                raise InputValidationError("Don't have access to the optimizer name")
            
            # prepare the arguments to be passed to the optimizer class
            optimizer_argsstr = "atoms, " + convert_the_args(optimizer.pop("args",[]))
            
            # prepare the arguments to be passed to optimizer.run()
            optimizer_runargsstr = convert_the_args(optimizer.pop("run_args",[]))
            
            # prepare the import string
            optimizer_import_string = get_optimizer_impstr(optimizer_name)
            
        # ================= determine the calculator name and its import ====
        
        calculator = parameters_dict.pop("calculator",{})
        calculator_import_string = get_calculator_impstr(calculator.pop("name",None))
        
        # =================== prepare the arguments for the calculator call
        
        read_calc_args = calculator.pop("args",[])
        #calc_args = calculator.pop("args",None)
        if read_calc_args is None:
            calc_argsstr = ""
        else:
            # transform a in "a" if a is a string (needed for formatting)
            calc_args = {}
            for k,v in read_calc_args.iteritems():
                if isinstance(v, basestring):
                    the_v = '"{}"'.format(v)
                else:
                    the_v = v
                calc_args[k] = the_v
            
            def return_a_function(v):
                try:
                    has_magic = "@function" in v.keys()
                except AttributeError:
                    has_magic = False
                
                if has_magic:
                    
                    args_dict = {}
                    for k2,v2 in v['args'].iteritems():
                        if isinstance(v2,basestring):
                            the_v = '"{}"'.format(v2)
                        else:
                            the_v = v2
                        args_dict[k2] = the_v
                    
                    v2 = "{}({})".format(v['@function'],
                                         ", ".join(["{}={}".format(k_,v_) 
                                            for k_,v_ in args_dict.iteritems()]))
                    return v2
                else:
                    return v
            
            tmp_list = [ "{}={}".format(k,return_a_function(v)) 
                         for k,v in calc_args.iteritems() ]
            
            calc_argsstr = ", ".join( tmp_list )

            # add kpoints if present
            if kpoints:
                #TODO: here only the mesh is supported
                # maybe kpoint lists are supported as well in ASE calculators
                try:
                    mesh = kpoints.get_kpoints_mesh()[0]
                except AttributeError:
                    raise InputValidationError("Coudn't find a mesh of kpoints"
                                               " in the KpointsData")
                calc_argsstr = ", ".join( [calc_argsstr] + ["kpts=({},{},{})".format( *mesh )] )
                        
        # =============== prepare the methods of atoms.get(), to save results
        
        atoms_getters = default_atoms_getters + convert_the_getters( parameters_dict.pop("atoms_getters",[]) )
        
        # =============== prepare the methods of calculator.get(), to save results
        
        calculator_getters = convert_the_getters( parameters_dict.pop("calculator_getters",[]) )
        
        # ===================== build the strings with the module imports
        
        all_imports = ["import ase", 'import ase.io', "import json",
                       "import numpy", calculator_import_string]
        
        if optimizer is not None:
            all_imports.append(optimizer_import_string)

        try:
            if "PW" in calc_args['mode'].values():
                all_imports.append("from gpaw import PW")
        except KeyError:
            pass
        
        extra_imports = parameters_dict.pop("extra_imports",[])
        for i in extra_imports:
            if isinstance(i,basestring):
                all_imports.append("import {}".format(i))
            elif isinstance(i,(list,tuple)):
                if not all( [isinstance(j,basestring) for j in i] ):
                    raise ValueError("extra import must contain strings")
                if len(i)==2:
                    all_imports.append("from {} import {}".format(*i))
                elif len(i)==3:
                    all_imports.append("from {} import {} as {}".format(*i))
                else:
                    raise ValueError("format for extra imports not recognized")
            else:
                raise ValueError("format for extra imports not recognized")
        
        if self.get_withmpi():
            all_imports.append( "from ase.parallel import paropen" )
        
        all_imports_string = "\n".join(all_imports) + "\n"
        
        # =================== prepare the python script ========================
        
        input_txt = ""
        input_txt += get_file_header()
        input_txt += "# calculation pk: {}\n".format(self.pk)
        input_txt += "\n"
        input_txt += all_imports_string
        input_txt += "\n"
        
        pre_lines = parameters_dict.pop("pre_lines",None)
        if pre_lines is not None:
            if not isinstance(pre_lines,(list,tuple)):
                raise ValueError("Prelines must be a list of strings")
            if not all( [isinstance(_,basestring) for _ in pre_lines] ):
                raise ValueError("Prelines must be a list of strings")
            input_txt += "\n".join(pre_lines) + "\n\n"
        
        input_txt += "atoms = ase.io.read('{}')\n".format(self._input_aseatoms)
        input_txt += "\n"
        input_txt += "calculator = custom_calculator({})\n".format(calc_argsstr)
        input_txt += "atoms.set_calculator(calculator)\n"
        input_txt += "\n"
        
        if optimizer is not None:
            # here block the trajectory file name: trajectory = 'aiida.traj'
            input_txt += "optimizer = custom_optimizer({})\n".format(optimizer_argsstr)
            input_txt += "optimizer.run({})\n".format(optimizer_runargsstr)
            input_txt += "\n"
        
        # now dump / calculate the results
        input_txt += "results = {}\n"
        for getter,getter_args in atoms_getters:
            input_txt += "results['{}'] = atoms.get_{}({})\n".format(getter,
                                                                     getter,
                                                                     getter_args)
        input_txt += "\n"
        
        for getter,getter_args in calculator_getters:
            input_txt += "results['{}'] = calculator.get_{}({})\n".format(getter,
                                                                          getter,
                                                                          getter_args) 
        input_txt += "\n"
        
        # Convert to lists
        input_txt += "for k,v in results.iteritems():\n"
        input_txt += "    if isinstance(results[k],(numpy.matrix,numpy.ndarray)):\n"
        input_txt += "        results[k] = results[k].tolist()\n"
        
        input_txt += "\n"
        
        post_lines = parameters_dict.pop("post_lines",None)
        if post_lines is not None:
            if not isinstance(post_lines,(list,tuple)):
                raise ValueError("Postlines must be a list of strings")
            if not all( [isinstance(_,basestring) for _ in post_lines] ):
                raise ValueError("Postlines must be a list of strings")
            input_txt += "\n".join(post_lines) + "\n\n"

        # Dump results to file        
        right_open = "paropen" if self.get_withmpi() else "open"
        input_txt += "with {}('{}', 'w') as f:\n".format(right_open, self._OUTPUT_FILE_NAME)
        input_txt += "    json.dump(results,f)"
        input_txt += "\n"
        
        # Dump trajectory if present
        if optimizer is not None:
            input_txt += "atoms.write('{}')\n".format(self._output_aseatoms)
            input_txt += "\n"
        
        # write all the input script to a file
        input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME)
        with open(input_filename,'w') as infile:
            infile.write(input_txt)
            
        # ============================ calcinfo ================================
        
        # TODO: look at the qmmm infoL: it might be necessary to put
        # some singlefiles in the directory.
        # right now it has to be taken care in the pre_lines
        
        local_copy_list = []
        remote_copy_list = [] 
        additional_retrieve_list = settings_dict.pop("ADDITIONAL_RETRIEVE_LIST",[])
        
        calcinfo = CalcInfo()
        
        calcinfo.uuid = self.uuid
        # Empty command line by default
        # calcinfo.cmdline_params = settings_dict.pop('CMDLINE', [])
        calcinfo.local_copy_list = local_copy_list
        calcinfo.remote_copy_list = remote_copy_list
        
        codeinfo = CodeInfo()
        codeinfo.cmdline_params = [self._INPUT_FILE_NAME]
        #calcinfo.stdin_name = self._INPUT_FILE_NAME
        codeinfo.stdout_name = self._TXT_OUTPUT_FILE_NAME
        codeinfo.code_uuid = code.uuid
        calcinfo.codes_info = [codeinfo]
        
        # Retrieve files
        calcinfo.retrieve_list = []
        calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME)
        calcinfo.retrieve_list.append(self._output_aseatoms)
        calcinfo.retrieve_list += additional_retrieve_list
        
        # TODO: I should have two ways of running it: with gpaw-python in parallel
        # and executing python if in serial
        
        return calcinfo